AT_abc442_f [ABC442F] Diagonal Separation 2
tokitsukaze · · 题解
分享一种比较有趣(?)的思考方向。
Solution
题意相当于是求一条从左下到右上的阶梯状折线,满足左上半部分是白色,右下半部分是黑色,使得修改次数最少。
我们从折线角度考虑。会发现:从左下角出发,往上走一格,这个点往右的一行所有格子必须全是黑色;往右走一格,这个点往上的一列所有格子必须全是白色。
举个例子:
左下角开始,往右移动一格,往上移动一格,往上移动一格,往右移动一格,往上移动一格。
画一画图大概长这样:
??? .?? .?? .?? ..? ..#
??? -> .?? -> .?? -> .## -> .## -> .##
??? .?? .## .## .## .##
所以只要预处理出:每个点上面一列全修改成白色的最少次数;右边一行全修改成黑色的的最少次数。然后从左下开始做 dp 即可。
最后取答案的时候要注意,最后折线的位置可能是第
时间复杂度
Code
AC记录
:::success[代码]
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const ll LLINF=0x3f3f3f3f3f3f3f3fLL;
const int MAX=5000+10;
char mp[MAX][MAX];
int w[MAX][MAX],b[MAX][MAX],dp[MAX][MAX];
int main()
{
int n,i,j,ans;
scanf("%d",&n);
for(i=1;i<=n;i++) scanf("%s",mp[i]+1);
memset(w,0,sizeof w);
for(j=1;j<=n;j++)
{
for(i=1;i<=n;i++)
{
w[i][j]=w[i-1][j]+(mp[i][j]=='#');
}
}
memset(b,0,sizeof b);
for(i=1;i<=n;i++)
{
for(j=n;j;j--)
{
b[i][j]=b[i][j+1]+(mp[i][j]=='.');
}
}
memset(dp,0x3f,sizeof dp);
dp[n][1]=0;
for(i=n;i;i--)
{
for(j=1;j<=n;j++)
{
dp[i][j+1]=min(dp[i][j+1],dp[i][j]+w[i][j]);
dp[i-1][j]=min(dp[i-1][j],dp[i][j]+b[i][j]);
}
}
ans=INF;
for(i=0;i<=n+1;i++) ans=min(ans,dp[i][n+1]);
for(j=0;j<=n+1;j++) ans=min(ans,dp[0][j]);
printf("%d\n",ans);
return 0;
}
:::