• CF1592F Alice and Recoloring


    题目

    有一个 (n imes m) 的矩阵,位置 ((i,j)) 上的颜色是白色或者黑色,最小化变成全白的代价,操作如下:

    • 反转一个包含 ((1,1)) 的子矩阵,花费为 (1)
    • 反转一个包含 ((n,1)) 的子矩阵,花费为 (2/3)
    • 反转一个包含 ((1,m)) 的子矩阵,花费为 (4)
    • 反转一个包含 ((n,m)) 的子矩阵,花费为 (3/2)

    (n,mleq 500)

    Easy version

    容易发现第 (2,3) 种操作一定没用,因为它们都可以被一操作替换。

    因为反转操作是范围修改,我们尝试使用类似差分的技巧让它修改某个单点值,把白色当成 (0),把黑色当成 (1),设 (b_{i,j}=a_{i,j}oplus a_{i,j+1}oplus a_{i+1,j}oplus a_{i+1,j+1}),最后的状态是全为 (0)

    那么操作 (1) 相当于反转 (b_{i,j}),操作 (4) 相当于反转 (b_{i-1,m},b_{n,j-1},b_{i-1,j-1},b_{n,m})

    根据贪心当且仅当四个位置都有值的时候才会使用 (4) 操作,否则使用 (1) 操作是最优的,那么我们暴力判断有没有这样的位置 ((i,j)),如果没有答案就是 (b_{x,y}=1) 的个数,否则答案需要减去 (1)

    Hard version

    因为 (4) 操作的代价变小了,所以它的出场机会会变多,不妨先不考虑 (b_{n,m})(影响太小)

    那么如果 (b_{i-1,m},b_{n,j-1},b_{i-1,j-1}) 三个位置都有值,就可以使用 (4) 操作来减少 (1) 的代价,否则都不能减少代价。很容易看出这是一个行和列的匹配问题,我们找到最大匹配就是最大代价减少量。

    这时候再来考虑 (b_{n,m}),如果匹配个数是奇数,若 (b_{n,m}=0) 则需要多花费 (1) 的代价(但是暴力匹配还是最优的),若 (b_{n,m}=0) 则可以减少 (1) 的代价,如果匹配个数为偶数则无影响。

    总结

    本题最关键的技巧是广义差分,一维数组上我们通过差分可以把区间修改变成单点修改。在矩阵上同样可以使用差分技巧,那么可以把矩阵操作变成单点操作,用四个相邻位置来定义差分值即可。

    //I might be staring at my last chance
    #include <cstdio>
    const int M = 505;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,ans,a[M][M],b[M][M];char s[M][M];
    signed main()
    {
    	n=read();m=read();
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%s",s[i]+1);
    		for(int j=1;j<=m;j++)
    			a[i][j]=s[i][j]=='B';
    	}
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    		{
    			b[i][j]=a[i][j]^a[i+1][j]^
    			a[i][j+1]^a[i+1][j+1];
    			if(b[i][j]) ans++;
    		}
    	int sub=0;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			if(b[n][m] && b[i-1][m]
    			&& b[n][j-1] && b[i-1][j-1])
    				sub=1;
    	printf("%d
    ",ans-sub);
    }
    
    //I might be staring at my last chance
    #include <cstdio>
    #include <iostream> 
    #include <queue>
    using namespace std;
    const int M = 1005;
    const int inf = 0x3f3f3f3f;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,ans,tot,f[M],a[M][M],b[M][M];
    int S,T,mt,dis[M],cur[M];char s[M][M];
    struct edge{int v,c,next;} e[M*M];
    void add(int u,int v,int c)
    {
    	e[++tot]=edge{v,c,f[u]},f[u]=tot;
    	e[++tot]=edge{u,0,f[v]},f[v]=tot;
    }
    int bfs()
    {
    	for(int i=0;i<=T;i++) dis[i]=0;
    	queue<int> q;
    	q.push(S);dis[S]=1;
    	while(!q.empty())
    	{
    		int u=q.front();q.pop();
    		if(u==T) return 1;
    		for(int i=f[u];i;i=e[i].next)
    		{
    			int v=e[i].v;
    			if(!dis[v] && e[i].c>0)
    			{
    				dis[v]=dis[u]+1;
    				q.push(v);
    			}
    		}
    	}
    	return 0;
    }
    int dfs(int u,int ept)
    {
    	if(u==T) return ept;
    	int flow=0,tmp=0;
    	for(int &i=cur[u];i;i=e[i].next)
    	{
    		int v=e[i].v;
    		if(dis[v]==dis[u]+1 && e[i].c>0)
    		{
    			tmp=dfs(v,min(ept,e[i].c));
    			if(!tmp) continue;
    			ept-=tmp;
    			e[i].c-=tmp;
    			e[i^1].c+=tmp;
    			flow+=tmp;
    			if(!ept) break;
    		}
    	}
    	return flow;
    }
    signed main()
    {
    	n=read();m=read();
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%s",s[i]+1);
    		for(int j=1;j<=m;j++)
    			a[i][j]=s[i][j]=='B';
    	}
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    		{
    			b[i][j]=a[i][j]^a[i+1][j]^
    			a[i][j+1]^a[i+1][j+1];
    			if(b[i][j]) ans++;
    		}
    	S=0;T=n+m+1;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			if(b[i-1][m] && b[n][j-1] && b[i-1][j-1])
    				add(i,n+j,1);
    	for(int i=1;i<=n;i++)
    		add(S,i,1);
    	for(int i=1;i<=m;i++)
    		add(i+n,T,1);
    	while(bfs())
    	{
    		for(int i=0;i<=T;i++)
    			cur[i]=f[i];
    		mt+=dfs(S,inf);
    	}
    	if(mt%2)
    	{
    		if(a[n][m]==0) ans++;
    		else ans--;
    	}
    	printf("%d
    ",ans-mt);
    }
    
  • 相关阅读:
    ef core中如何实现多对多的表映射关系
    asp.net mvc 实现简单的实时消息推送
    C#中三层架构UI、BLL、DAL、Model实际操作
    搭建连接MySql的三层架构的ASP.NetCore2.0的WebApi
    基于.NET Core 框架搭建WebApi项目
    16位GUID
    VS2017企业版的密钥
    通过微软的cors类库,让ASP.NET Web API 支持 CORS
    Web API 跨域访问(CORS)
    [HDU1394]Minimum Inversion Number
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15386974.html
Copyright © 2020-2023  润新知