日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P1174 打砖块

發(fā)布時間:2023/12/3 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P1174 打砖块 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

P1174 打磚塊

題意:

題解:

參考題解:
I_AM_HelloWord
danxmz2006
這兩個博客結(jié)合看,大致就能理解

我們只在N處轉(zhuǎn)移,面對Y類的塊無需決策,因為Y類的塊可以一直打
不同的打磚塊的順序,決定了我們最后的分數(shù)情況,因此有個結(jié)論:
我們最后一個打的磚塊一定是N類磚塊,除非所有的磚塊都已經(jīng)打完了
我們從這點出發(fā)開始轉(zhuǎn)移:
對于計算[1,j]列的最優(yōu)解時:

  • 第j列根本不打(此時直接繼承[1,j-1]的狀態(tài))
  • 最后一發(fā)子彈在第j列上
  • 最后一發(fā)子彈在[1,j-1]列
  • 最后一發(fā)子彈還未出現(xiàn)(即最后一發(fā)子彈將會在[j+1,m]中,不過我們無需管)
  • 狀態(tài)轉(zhuǎn)移中我們需要一些輔助變量:
    sum1[i][j]表示對于第i列,打到第j行所得分數(shù)
    sum2[i][j]表示對于第i列,打到第j行同時與此塊相鄰的一連串Y全部打掉能得到的分數(shù)(可以理解成在第i列,第j行開始打塊,所能打的最大分)
    tot[i][j]:表示對于第i列打到第j行所需要的子彈數(shù)量(對于N類磚塊,數(shù)量+1,對于Y類不變)
    設dp[j][tk][0/1]:表示[1,j]列中,用tk發(fā)子彈,最后一發(fā)子彈是否在[1,j]列中,0表示在,1表示不在
    這樣轉(zhuǎn)移我們充分考慮了以每一列是否為結(jié)尾的情況

    轉(zhuǎn)移1:
    //直接繼承上一列的狀態(tài)

    dp[j][tk][0]= dp[j - 1][tk][0]; dp[j][tk][1]= dp[j - 1][tk][1];

    轉(zhuǎn)移2:

    最后一發(fā)子彈在[1,j]中,同時在第j列,因此不在[1,j-1]中

    dp[j][k][0]=max(dp[j-1][k-tot[j][i]][1]+sum1[j][i])

    轉(zhuǎn)移3:
    最后一發(fā)子彈在[1,j]中,但不在第j列,因此在[1,j-1]中

    dp[j][k][0]=max(dp[j-1][k-tot[j][i]][0]+sum2[j][i])

    轉(zhuǎn)移4:
    最后一發(fā)子彈不在[1,j]中,因此[1,j-1]必然沒有,第j列也沒有

    dp[j][k][1]=max(dp[j-1][k-tot[j][i]][1]+sum2[j][i])

    代碼:

    #include <bits/stdc++.h> #include <unordered_map> #define debug(a, b) printf("%s = %d\n", a, b); using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> PII; clock_t startTime, endTime; //Fe~Jozky const ll INF_ll= 1e18; const int INF_int= 0x3f3f3f3f; void read(){}; template <typename _Tp, typename... _Tps> void read(_Tp& x, _Tps&... Ar) {x= 0;char c= getchar();bool flag= 0;while (c < '0' || c > '9')flag|= (c == '-'), c= getchar();while (c >= '0' && c <= '9')x= (x << 3) + (x << 1) + (c ^ 48), c= getchar();if (flag)x= -x;read(Ar...); } template <typename T> inline void write(T x) {if (x < 0) {x= ~(x - 1);putchar('-');}if (x > 9)write(x / 10);putchar(x % 10 + '0'); } void rd_test() { #ifdef LOCALstartTime= clock();freopen("in.txt", "r", stdin); #endif } void Time_test() { #ifdef LOCALendTime= clock();printf("\nRun Time:%lfs\n", (double)(endTime - startTime) / CLOCKS_PER_SEC); #endif } const int maxn= 210; int cur[maxn], tot[maxn][maxn], a[maxn][maxn]; int b[maxn][maxn]; int sum1[maxn][maxn]; int sum2[maxn][maxn]; int dp[maxn][maxn][2]; int main() {//rd_test();int n, m, k;read(n, m, k);//n行m列k個子彈// memset(a, 0, sizeof(a));// memset(b, 0, sizeof(b));// memset(sum2, 0, sizeof(sum2));// memset(sum1, 0, sizeof(sum1));// memset(cur, 0, sizeof(cur));// memset(tot, 0, sizeof(tot));//memset(cur,0x3f3f3f,sizeof(cur));for (int i= n; i >= 1; i--) {for (int j= 1; j <= m; j++) {read(a[i][j]);char ch= getchar();while (ch < 'A' || ch > 'Z')ch= getchar();if (ch == 'Y')b[i][j]= 1; //對于Y磚標記}}int ans= 0;for (int j= 1; j <= m; j++) {for (int i= 1; i <= n; i++) {if (b[i][j] == 0) //如果是N{cur[j]= i; //記錄了每一列第一次出現(xiàn)N的位置break;}ans+= a[i][j]; //記錄Y的分數(shù)}}//先求sum1for (int j= 1; j <= m; j++) {for (int i= cur[j]; i <= n; i++) {sum1[j][i]= sum1[j][i - 1] + a[i][j];sum2[j][i]= sum1[j][i];}}//利用求sum2for (int j= 1; j <= m; j++) {tot[j][cur[j]]= 1; //第j列打到第cur[j]行所需的子彈數(shù)量for (int i= cur[j]; i <= n; i++) {int idx= i;while (b[idx + 1][j]) //如果第idx+1行的第j列idx++;//找到這一列連續(xù)Y的位置,用于更新sum2sum2[j][i]= sum1[j][idx];//sum2比起sum1多的是連續(xù)Y的數(shù)量,所以直接更新sum1[j][idx]tot[j][idx + 1]= tot[j][i] + 1;//只需要多一個子彈即可,因為打Y不耗費額外的i= idx;}}//以上為更新sum1和sum2的步驟for (int j= 0; j <= m; j++)dp[j][0][0]= -INF_int;for (int j= 1; j <= m; j++) { //[1,j]列中for (int tk= 1; tk <= k; tk++) { //用了k發(fā)子彈dp[j][tk][0]= dp[j - 1][tk][0]; //直接繼承上一列的狀態(tài)dp[j][tk][1]= dp[j - 1][tk][1];if(cur[j]==0)continue;//說明這一列都是Y,直接跳過就行 for (int i= cur[j]; i <= n; i++) //枚舉每一行if (!b[i][j] && tk >= tot[j][i]) {//如果第i行,第j列是N,并且子彈數(shù)量大于需要的數(shù)量//就進行狀態(tài)轉(zhuǎn)移dp[j][tk][0]= max(dp[j][tk][0], dp[j - 1][tk - tot[j][i]][1] + sum1[j][i]);dp[j][tk][0]= max(dp[j][tk][0], dp[j - 1][tk - tot[j][i]][0] + sum2[j][i]);dp[j][tk][1]= max(dp[j][tk][1], dp[j - 1][tk - tot[j][i]][1] + sum2[j][i]);}}}printf("%d\n", dp[m][k][0] + ans);return 0;//Time_test(); } /* 1 5 185 3985 Y 6951 N 2151 Y 1749 N 7413 Y */

    隊友的代碼:

    // Problem: P1174 打磚塊 // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P1174 // Memory Limit: 125 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org)//#pragma GCC target("avx") //#pragma GCC optimize(2) //#pragma GCC optimize(3) //#pragma GCC optimize("Ofast") // created by myq #include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> #include<unordered_map> #include<unordered_set> using namespace std; typedef long long ll; #define x first #define y second #define int long long typedef pair<int,int> pii;const int N=410;int n,m,k;char g[N][N];int mp[N][N]; int com[N]; bool st[N][N]; int base; int f[N][N][2]; int res=0; int maxv=0; signed main() { cin>>n>>m>>k;int cnt=0;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){cin>>mp[i][j]>>g[i][j];}}memset(f,-0x3f,sizeof f);f[0][k][0]=0;for(int i=1;i<=m;i++){for(int j=0;j<=k;j++){ f[i][j][0]=f[i-1][j][0];f[i][j][1]=f[i-1][j][1];int sum=0;int sum2=0;bool flag=false;for(int sx=n,sy=i;sx>=1;sx--){sum+=(g[sx][sy]=='Y'?0:-1);if(j==0 && g[sx][sy]=='Y') flag=true;sum2+=mp[sx][sy];//solve 0 if( j-sum<=k){f[i][j][0]=max(f[i][j][0],f[i-1][j-sum][0]+sum2);f[i][j][1]=max(f[i][j][1],f[i-1][j-sum][1]+sum2);}// solve 1if(!flag && j-sum<=k&& g[sx][sy]=='N'){f[i][j][1]=max(f[i][j][1],f[i-1][j-sum][0]+sum2);}}}}for(int i=0;i<=k;i++)res=max(res,f[m][i][1]);cout<<res<<endl;return 0;} /** * In every life we have some trouble * When you worry you make it double * Don't worry,be happy. **/ 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

    總結(jié)

    以上是生活随笔為你收集整理的P1174 打砖块的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。