「Luogu4158」[SCOI2009]粉刷匠
「Luogu4158」[SCOI2009]粉刷匠
problem
題目描述
\(windy\)有 \(N\) 條木板需要被粉刷。 每條木板被分為 \(M\) 個格子。 每個格子要被刷成紅色或藍色。
\(windy\)每次粉刷,只能選擇一條木板上一段連續的格子,然後塗上一種顏色。 每個格子最多只能被粉刷一次。
如果\(windy\)只能粉刷 \(T\) 次,他最多能正確粉刷多少格子?
一個格子如果未被粉刷或者被粉刷錯顏色,就算錯誤粉刷。
輸入輸出格式
輸入格式:
第一行包含三個整數,\(N\) \(M\) \(T\)。
接下來有\(N\)行,每行一個長度為\(M\)的字符串,‘0‘表示紅色,‘1‘表示藍色。
輸出格式:
包含一個整數,最多能正確粉刷的格子數。
輸入輸出樣例
輸入樣例#1:
3 6 3
111111
000000
001100
輸出樣例#1:
16
說明
\(30\%\)的數據,滿足 \(1 \le N,M \le 10\) ; \(0 \le T \le 100\) 。
\(100\%\)的數據,滿足 \(1 \le N,M <= 50\) ; \(0 \le T \le 2500\) 。
Solution
蒟蒻看到這題想了\(n\)多種完全不正確的處理方法,如果是在考場上估計已經光速涼涼了\(QAQ\)
對於每一行,我們可以把它分成若幹個顏色不同的連續段(對應若幹次顏色不同的粉刷),從左到右考慮
註意到題目:
一個格子如果未被粉刷或者被粉刷錯顏色,就算錯誤粉刷。
意思就是不刷白不刷
如果是顏色不對,多刷這一格不會比不刷差,就不需要考慮不刷的情況
所以我們有:
狀態:設\(dp_{i,j,k,0/1}\)表示當前枚舉到第\(i\)行,第\(j\)個格子,已經塗了\(k\)次(分成了\(k\)段),當前格子塗的顏色是\(0/1\)
方程:
\[dp_{i,j,k,x}=max(dp_{i,j-1,k,x},dp_{i,j-1,k-1,x\space xor\space 1})+[x=color_{i,j}]\]
(方括號是艾弗森括號,當其中的條件為真時值為\(1\),否則為\(0\))
這個轉移應該很好理解吧
處理完每一行之後,\(max(dp_{i,m,k,0},dp_{i,m,k,1})\)
這樣,每一行作為一組,原問題就轉化為一個分組背包問題,在此不再贅述
Code
代碼中所用的字母與上述轉移方程略有不同,請註意辨別
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#define maxn 55
#define maxm 55
#define maxt 2505
using namespace std;
typedef long long ll;
template <typename T> void read(T &t)
{
t=0;int f=0;char c=getchar();
while(!isdigit(c)){f|=c=='-';c=getchar();}
while(isdigit(c)){t=t*10+c-'0';c=getchar();}
if(f)t=-t;
}
int n,m,t;
int col[maxn][maxm];
int dp[maxn][maxm][maxm][2],tdp[maxt];
int main()
{
read(n),read(m),read(t);
for(register int i=1;i<=n;++i)
{
char c[maxm];
scanf("%s",c+1);
for(register int j=1;j<=m;++j)
col[i][j]=c[j]-'0';
}
for(register int li=1;li<=n;++li)
for(register int i=1;i<=m;++i)
for(register int k=1;k<=min(t,m);++k)
for(register int x=0;x<=1;++x)
dp[li][i][k][x]=max(dp[li][i-1][k][x],dp[li][i-1][k-1][x^1])+(x==col[li][i]);
for(register int i=1;i<=n;++i)
for(register int j=t;j>=0;--j)
for(register int k=1;k<=min(j,m);++k)
tdp[j]=max(tdp[j],tdp[j-k]+max(dp[i][m][k][0],dp[i][m][k][1]));
printf("%d",tdp[t]);
return 0;
}
「Luogu4158」[SCOI2009]粉刷匠