https://codeforces.com/problemset/problem/225/C
这个题目和之前一个题目很像 https://www.cnblogs.com/EchoZQN/p/10900373.html
只是这个数据范围更大一些,
不过刚开始我真的没有看出来。。。。
这个就是整列整列的处理,所以还是一样枚举当前的连续的j
dp[i][j][k] 这个k只有两个取值,一个是0,一个是1,0 代表白色,1代表黑色。
这个定义就是dp[i][j][0] 前面i个连续j个白色的列需要粉刷的最少的砖的数量。
另外一个同样,
所以按照之前的想法,很贱的就可以知道会有两种情况,一个是j==1 那就说明是之前的情况推过来的,因为之前的这个j不确定,
所以这里要枚举每一种情况。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<queue>
#include<vector>
#define inf 0x3f3f3f3f
#define debug(x) cout<<"-----"<<" x = "<<x<<"-----"<<endl
using namespace std;
typedef long long ll;
const int maxn = 5e3 + 10;
ll dp[1010][1010][2];
char s[1010][1010];
int b[1010], w[1010];
int main()
{
int n, m, x, y;
scanf("%d%d%d%d", &n, &m, &x, &y);
for (int i = 1; i <= n; i++) scanf("%s", s[i] + 1);
for(int j=1;j<=m;j++)
{
for(int i=1;i<=n;i++)
{
if (s[i][j] == '.') w[j]++;
else b[j]++;
}
}
memset(dp, inf, sizeof(dp));
dp[1][1][0] = b[1];
dp[1][1][1] = w[1];
for(int i=1;i<=m;i++)
{
for(int j=1;j<=y&&j<=i;j++)
{
if(j!=1)
{
dp[i][j][0] = dp[i-1][j-1][0] + b[i];
dp[i][j][1] = dp[i-1][j-1][1] + w[i];
}
else
{
for(int k=x;k<=y;k++)
{
dp[i][j][0] = min(dp[i][j][0], dp[i-1][k][1] + b[i]);
dp[i][j][1] = min(dp[i][j][1], dp[i-1][k][0] + w[i]);
}
}
// printf("dp[%d][%d][0]=%lld
", i, j, dp[i][j][0]);
// printf("dp[%d][%d][1]=%lld
", i, j, dp[i][j][1]);
}
}
ll ans = inf;
for(int i=x;i<=y;i++)
{
ans = min(ans, dp[m][i][0]);
ans = min(ans, dp[m][i][1]);
}
printf("%lld
", ans);
return 0;
}