• AGC051C


    一个无限大的网格,有些点染成了黑色。每次可以把一个2*3的矩形反色。

    可以操作任意多次,求最后保留的黑点最少是多少。

    (nle 10^5)


    考虑什么样的状态可以到达。

    不变量:

    1. 每列的异或和,记为(p_i)
    2. 每行中,列模(3)分组的异或和记为(q_{i,k},k=0,1,2)(q_i)要么相等,要么全部相反。

    接下来证明其充分性:

    如果状态(A)能到(B),由于转移是双向的,所以如果(A,B)能转移到同一个状态,那么可以互相到达。

    先强行把所有的(xge 2,yge 3)的黑点全部染白。现在平面分成了四个部分,对这四个部分分别分析,发现确实等价。

    (t_k=sum_{i}p_{3i+k},s_k=sum_iq_{i,k})。显然必须满足(t_kequiv s_kpmod 2)

    你需要安排(q_i),得到(s_k)(t_k)是给定的。则贡献为(sum_{k}max(s_k,t_k))(此时可以视作一个矩阵,有些列的异或和为(1),有些行的异或和为(1),并且两者个数之差为偶数。把这些行列交成的子矩阵拉出来,成为一个长方形,把长方形分割出一个正方形放对角线,剩下的部分全部放一排)。

    问题相当于:你有一些向量((0,0,0),(1,0,0),(0,1,0),(0,0,1)),可以把一些向量取反。把这些向量求和得到(s),最大化(sum_kmax(s_k,t_k))

    枚举每个向量取反个数的奇偶性。然后对于(s_k-t_k)最大的,尝试把偶数个向量(k)取反使其变小。


    using namespace std;
    #include <bits/stdc++.h>
    #define N 100005
    int n;
    map<int,int> p,q;
    int t[3];
    int c[4];
    int id(int x){
    	if (!(x==0 || x==1 || x==2 || x==4))
    		x^=7;
    	if (x==0) return 3;
    	if (x==1) return 0;
    	if (x==2) return 1;
    	if (x==4) return 2;
    }
    int s[3];
    int main(){
    	freopen("in.txt","r",stdin);
    	scanf("%d",&n);
    	for (int i=1;i<=n;++i){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		p[y]^=1;
    		q[x]^=1<<y%3;
    	}
    	for (auto it=p.begin();it!=p.end();++it)
    		t[it->first%3]+=it->second;
    	for (auto it=q.begin();it!=q.end();++it)
    		c[id(it->second)]++;
    	int ans=INT_MAX;
    	int r[4];
    	for (r[0]=0;r[0]<=1 && r[0]<=c[0];++r[0])
    		for (r[1]=0;r[1]<=1 && r[1]<=c[1];++r[1])
    			for (r[2]=0;r[2]<=1 && r[2]<=c[2];++r[2])
    				for (r[3]=0;r[3]<=1 && r[3]<=c[3];++r[3]){
    					s[0]=(c[0]-r[0])+r[1]+r[2]+r[3];
    					s[1]=r[0]+(c[1]-r[1])+r[2]+r[3];
    					s[2]=r[0]+r[1]+(c[2]-r[2])+r[3];
    					if (((s[0]^t[0])|(s[1]^t[1])|(s[2]^t[2]))&1)
    						continue;
    					int fir=0,sec=-1;
    					for (int j=1;j<=2;++j)
    						if (s[j]-t[j]>s[fir]-t[fir])
    							sec=fir,fir=j;
    						else if (sec==-1 && s[j]-t[j]>s[sec]-t[sec])
    							sec=j;
    					if (s[fir]-t[fir]>0 && s[sec]-t[sec]<0){
    						int d=min(c[fir]-r[fir],min(s[fir]-t[fir],-(s[sec]-t[sec])))/2*2;
    						s[fir]-=d;
    						s[sec]+=d;
    						s[3^fir^sec]+=d;
    					}
    					ans=min(ans,max(s[0],t[0])+max(s[1],t[1])+max(s[2],t[2]));
    				}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Spring 控制器层如何调用DAO层
    Spring 工程分层
    spring boot工程如何启用 热启动功能
    Spring 视图层如何显示验证消息提示
    Sping POJO中如何添加验证规则和验证消息提示
    Spirng 分层,增加数据访问对象层
    Spring A 标签链接使用
    Spring 控制器重定向
    课程详情页之后台
    课程详情页之前台
  • 原文地址:https://www.cnblogs.com/jz-597/p/14512716.html
Copyright © 2020-2023  润新知