题解:CF225C Barcode

· · 题解

绿题做得最明白的一集。

这种问题我们可以分情况讨论,我们定义 dp_{0/1,i} 分别表示第 i 列颜色为白或黑时最小的修改次数,答案就取 dp_{0,m}dp_{1,m} 中最小的那个。

接下来考虑转移。我们需要枚举当前位置往后 x\sim y 的列数 j,将当前列 i 到往后的 j 列全部改成白色或黑色。因此我们不难得出转移:

dp_{0,i+j}=\max_{j\in[x,y]}dp_{1,i}+\text{sumwhite}(i-1,i+j)\\dp_{1,i+j}=\max_{j\in[x,y]}dp_{0,i}+\text{sumblack}(i-1,i+j)

其中 \text{sumwhite}\text{sumblack} 可以用前缀和优化,时间复杂度 \mathcal O(nm+my),可以通过本题。

::::success[Code]

#include<bits/stdc++.h>
using namespace std;
int dp[2][1005];
char c[1005][1005];
int bai[1005],hei[1005];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr),cout.tie(nullptr);
    int n,m,x,y;
    cin>>n>>m>>x>>y;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>c[i][j];
            bai[j]+=c[i][j]=='.';
            hei[j]+=c[i][j]=='#';
        }
    }
    for(int i=1;i<=m;i++){
        bai[i]+=bai[i-1];
        hei[i]+=hei[i-1];
    }
    memset(dp,0x3f,sizeof dp);
    dp[0][0]=0,dp[1][0]=0;
    for(int i=0;i<m;i++){
        for(int j=x;j<=y&&i+j<=m;j++){
            dp[0][i+j]=min(dp[0][i+j],dp[1][i]+bai[i+j]-bai[i]);
            dp[1][i+j]=min(dp[1][i+j],dp[0][i]+hei[i+j]-hei[i]);
        }
    }
    cout<<min(dp[0][m],dp[1][m]);
    return 0;
}

::::