【[SCOI2009]粉刷匠】
阿新 • • 發佈:2019-01-02
這好像是個暴力?
但是跑的挺快的
我們設\(dp[i][j][k]\)表示在第\(i\)行我們最遠染到的位置是\(j\),這一行上一共染了\(k\)次最多能染對多少個格子
理性分析一下啊,每一行最多也就染\(m\)次,這樣就能把這一行格子全部都染對
所以這個空間複雜度是\(nm^2\)的
之後考慮一下轉移
顯然這就是一個非常經典的斷點\(dp\)了,轉移為
\[dp[i][j][k]=max(dp[i][p][k-1]+max(s_0[p+1,j],s_1[p+1,j]))\]
\(s_0[p+1,j]\)表示這個區間內有幾個\(0\),後面那個也就是我們能夠正確覆蓋的格子數量
最後用分組揹包合併大案就好了
程式碼
#include<iostream> #include<cstring> #include<cstdio> #define max(a,b) ((a)>(b)?(a):(b)) #define re register int dp[51][51][51]; int pre[51][51][2]; char S[51][51]; int f[2501]; int n,m,T; int main() { scanf("%d%d%d",&n,&m,&T); for(re int i=1;i<=n;i++) { scanf("%s",S[i]+1); for(re int j=1;j<=m;j++) if(S[i][j]=='1') pre[i][j][1]=pre[i][j-1][1]+1,pre[i][j][0]=pre[i][j-1][0]; else pre[i][j][1]=pre[i][j-1][1],pre[i][j][0]=pre[i][j-1][0]+1; } for(re int i=1;i<=n;i++) for(re int j=1;j<=m;j++) for(re int k=1;k<=j;k++) for(re int p=0;p<j;p++) dp[i][j][k]=max(dp[i][j][k],dp[i][p][k-1]+max(pre[i][j][0]-pre[i][p][0],pre[i][j][1]-pre[i][p][1])); for(re int i=1;i<=n;i++) for(re int j=T;j>=0;j--) for(re int k=0;k<=m;k++) if(j-k>=0) f[j]=max(f[j],f[j-k]+dp[i][m][k]); printf("%d\n",f[T]); return 0; }