zoukankan      html  css  js  c++  java
  • CF1592F2 Alice and Recoloring 2

    目前在看贪心/构造/DP 杂题选做,发现一道非常不错的结论题,具有启发意义。

    先说明如下结论

    结论一:如何怎么样都不会使用二和三操作
    证明:
    二三操作显然可以通过两次一操作达到,而其操作费用大于两次一操作费用

    所以显然我们只会操作一四操作。

    那么我们发现翻转一整个矩形不好操作,翻转到一特定状态也不好处理,不如考虑倒序操作:即给定特定状态变为全白状态的费用,知其与原问题等价。

    然后我们处理翻转问题,我们考虑一个转换
    \(a_{i,j} = a_{i,j}\ xor\ a_{i+1,j}\ xor\ a_{i,j + 1}\ xor\ a_{i + 1,j + 1}\)
    我们发现全白时显然全等为\(0\)

    而一四操作我们可以将其本质变为:

    一操作:单点翻转\((x,y)\)

    四操作:四点翻转\((x,y),(x,m),(n,y),(n,m)\)

    那么问题变得显然起来。

    我们依旧给出了两个结论

    结论二:不用同时使用两个横坐标或竖坐标相等的四操作
    证明:其等价于修改四个任意散点,其可以等价于四次一操作的费用

    结论三:除非 \((x,y),(n,y),(x,m)\) 都为1,才会使用 \((x,y)\) 这一四操作
    证明:如果有一个不为\(1\),那么其有一个错误反转,我们需要其一个一操作反转回来,那么其等价于\(1 + 2 = 3\),可以使用一操作代替。

    那么经典问题转化为满足某种条件的改变行列取点数量。

    二分图上最大匹配即可。

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #define ll long long 
    #define N 30000
    
    int n,m;
    
    int head[N];
    
    int cnt = 1;
    
    struct P{
    	int to,next;
    	ll v;
    }e[N << 2];
    
    inline void add(int x,int y,int v){
    	e[++cnt].to = y;
    	e[cnt].v = v;
    	e[cnt].next = head[x];
    	head[x] = cnt;
    }
    
    std::queue<int>QWQ;
    ll dis[N];
    bool vis[N];
    
    int a[505][505];
    
    int s,t;
    
    inline bool bfs(){
    	for(int i = 1;i <= n + m + 2;++i)
    	dis[i] = 1e10,vis[i] = 0;
    	dis[s] = 0;
    	QWQ.push(s);
    	vis[s] = 1;
    	while(!QWQ.empty()){
    		int u = QWQ.front();
    		QWQ.pop();
    		vis[u] = 0;
    		for(int i = head[u];i;i = e[i].next){
    			int v = e[i].to;
    			if(dis[v] > dis[u] + 1 && e[i].v){
    				dis[v] = dis[u] + 1;
    				if(!vis[v])
    				vis[v] = 1,QWQ.push(v);
    			}
    		}
    	}
    	return dis[t] != 1e10;
    }
    
    inline ll dfs(int u,ll in){
    	ll out = 0;
    	if(u == t)
    	return in;
    	for(int i = head[u];i;i = e[i].next){
    		int v = e[i].to;
    		if(e[i].v && dis[v] == dis[u] + 1){
    			int to = dfs(v,std::min(e[i].v,in));
    			e[i].v -= to;
    			e[i ^ 1].v += to;
    			in -= to;
    			out += to;
    		}
    	}
    	if(out == 0)
    	dis[u] = 0;
    	return out;
    }
    
    inline int dinic(){
    	int ans = 0;
    	while(bfs())
    	ans += dfs(s,1e18);
    	return ans;
    }
    
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i = 1;i <= n;++i)
    	for(int j = 1;j <= m;++j){
    		char s = getchar();
    		while(s != 'W' && s != 'B')
    		s = getchar();
    		a[i][j] = (s == 'B');
    		s = '.';
    	}	
    	int ans = 0;
    	for(int i = 1;i <= n;++i)
    	for(int j = 1;j <= m;++j){
    	a[i][j] = a[i][j] ^ a[i + 1][j] ^ a[i + 1][j + 1] ^ a[i][j + 1];
    	}
    //	for(int i = 1;i <= n;++i,puts(""))
    //	for(int j = 1;j <= m;++j)
    //	std::cout<<a[i][j]<<" ";
    	for(int i = 1;i <= n;++i)
    	for(int j = 1;j <= m;++j){
    		if(a[i][m] && (a[n][j] && a[i][j])){
    			add(i,n + j,1);
    			add(n + j,i,0);
    		}
    	}
    	s = n + m + 1,t = n + m + 2;
    	for(int i = 1;i < n;++i)
    	add(s,i,1),add(i,s,0);
    	for(int j = 1;j < m;++j)
    	add(n + j,t,1),add(t,n + j,0);
    	int k = dinic();
    	a[n][m] = a[n][m] ^ (k & 1);
    	for(int i = 1;i <= n;++i)
    	for(int j = 1;j <= m;++j)
    	ans += a[i][j];
    	std::cout<<ans - k<<std::endl;
    }//注意建图后的点集大小
    
  • 相关阅读:
    HTML5存储
    HTML5全局属性和事件
    HTML5媒体(音频/视频)
    HTML5标签canvas制作动画
    HTML5标签canvas图像处理
    开发kendo-ui弹窗组件
    HTML5标签canvas制作平面图
    javascript匿名函数
    Javascript富文本编辑器
    快速排序算法(python版本)
  • 原文地址:https://www.cnblogs.com/dixiao/p/15628595.html
Copyright © 2011-2022 走看看