1. 程式人生 > >【[SCOI2009]粉刷匠】

【[SCOI2009]粉刷匠】

這好像是個暴力?

但是跑的挺快的

我們設\(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;
}