把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

CF1672G Cross Xor

题面传送门
发现自己之前在瞎逼逼,于是重新写了一篇。
首先我们发现如果我们对四个点\((x1,y1),(x1,y2),(x2,y1),(x2,y2)\),那么有且仅有这四个点会改变答案。
所以如果所有行列都是偶数个,那么就一定可以消完,因为可以将所有一都集中到同一行,因为每一列都是偶数所以一定可以消掉。
那么我们只需要让所有行列都变成偶数即可。
我们考虑一次操作的贡献,考虑对于行来说,如果列的个数为奇数,那么所有行的权值都会异或\(1\),否则除了这个位置以外的值会异或\(1\)。对于列同理。因此当所有行的异或和不同且列的个数为奇数,则一定无解,对于列也是这样。因此对行列奇偶性分类讨论:

Case 1: \(2\mid n,2\mid m\)

我们猜想一定有解。
给出构造证明:每次选取行为\(1\)的位置,然后对除了这一行的剩下操作一次,这个\(1\)就被消除了。

Case 2: \(2\mid n,2\nmid m\)

我们猜想只要行的异或和相同就一定有解,证明同Case 1。
问题是怎么统计答案,我们枚举每一行是啥,然后进去check即可,根据经典结论,如果一行的问号个数为\(k\),则贡献为\(2^{k-1}\)

Case 3: \(2\nmid n,2\mid m\)

同Case 2。

Case 4: \(2\nmid n,2\nmid m\)

同样猜想行的异或和和列的异或和都相同才能有解。
但是这个统计答案有点困难。我们建立一张二分图,行为左部点,列为右部点,则如果一个位置为?则将左右连一条边。这条边的意义是两边可以同时异或一。我们同样枚举行列应该是啥,然后异或完本来有的值之后答案作为每个点的权值。显然,如果一个联通块中异或和不为零,则无解,否则我们发现任取一棵生成树,都有唯一确定的方法全部置为\(0\),则方案数为\(2^{m-n+1}\)
时间复杂度\(O(nm)\)
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (100000+5)
#define M ((N<<2)+5)
#define K (350)
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-9)
#define ull unsigned ll
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((k+1)*(x)+(y))
#define R(n) (1ll*rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;vector<int> F[N];
int op[N],x,y,n,m,Sh,Ans[N],D1[N],D2[N];queue<int> Q;vector<int> Id;
struct Edge{int x,y;};vector<Edge>S;I bool cmp(Edge x,Edge y){return x.x^y.x?x.x<y.x:x.y<y.y;}struct Ques{int x,y,id;};vector<Ques> G;
namespace Tree{
	int F[N];I void Ins(int x,int y){while(x<=n) F[x]+=y,x+=x&-x;}I int Qry(int x){int Ans=0;while(x) Ans+=F[x],x-=x&-x;return Ans;}
}
I void Solve(vector<Edge> S,vector<Ques> G,vector<int> Id){
	if(G.empty()||S.empty()) return;int Ps=-1,x;Edge Ns;for(int i:Id) Tree::Ins(i,1);for(Edge i:S) x=Tree::Qry(i.y)-Tree::Qry(i.x-1),x=min(x,Id.size()-x),x>Ps&&(Ns=i,Ps=x);
	for(int i:Id) Tree::Ins(i,-1),F[i].clear();for(Edge i:S) F[i.x].PB(i.y),F[i.y].PB(i.x);//if(S.size()>1000)cerr<<S.size()<<' '<<G.size()<<' '<<Id.size()<<' '<<Ps<<'\n';
	for(int i:Id) D1[i]=D2[i]=1e9,op[i]=0;D1[Ns.x]=D2[Ns.y]=0;
	Q.push(Ns.x);while(!Q.empty()) {x=Q.front();Q.pop();for(int i:F[x]) D1[i]>D1[x]+1&&(Q.push(i),D1[i]=D1[x]+1);}
	Q.push(Ns.y);while(!Q.empty()) {x=Q.front();Q.pop();for(int i:F[x]) D2[i]>D2[x]+1&&(Q.push(i),D2[i]=D2[x]+1);}
	vector<int> I1,I2;vector<Edge> S1,S2;vector<Ques> G1,G2;I1.clear();I2.clear();S1.clear();S2.clear();G1.clear();G2.clear();
	for(Ques i:G) Ans[i.id]=min(min(min(D1[i.x]+D1[i.y],D2[i.x]+D2[i.y]),min(D1[i.x]+D2[i.y]+1,D1[i.y]+D2[i.x]+1)),Ans[i.id]);
	for(int i:Id) if(i>=Ns.x&&i<=Ns.y) op[i]=1,I1.PB(i);for(Ques i:G) op[i.x]==op[i.y]&&op[i.x]&&(G1.PB(i),0);for(Edge i:S) (i.x^Ns.x||i.y^Ns.y)&&op[i.x]==op[i.y]&&op[i.x]&&(S1.PB(i),0);
	for(int i:Id) if(i<=Ns.x||i>=Ns.y) op[i]=-1,I2.PB(i);for(Ques i:G) op[i.x]==op[i.y]&&op[i.x]==-1&&(G2.PB(i),0);for(Edge i:S) (i.x^Ns.x||i.y^Ns.y)&&op[i.x]==op[i.y]&&op[i.x]==-1&&(S2.PB(i),0);
	Solve(S1,G1,I1);Solve(S2,G2,I2);
} 
int main(){
	freopen("1.in","r",stdin);//freopen("karen.out","w",stdout);
	int i,j;scanf("%d",&n);for(i=1;i<=n;i++) S.PB((Edge){i,i%n+1});for(i=1;i<=n-3;i++) scanf("%d%d",&x,&y),S.PB((Edge){x,y});for(i=0;i<S.size();i++) S[i].x>S[i].y&&(swap(S[i].x,S[i].y),0);
	Me(Ans,0x3f);for(i=1;i<=n;i++) Id.PB(i);scanf("%d",&m);for(i=1;i<=m;i++) scanf("%d%d",&x,&y),x^y?(G.PB((Ques){x,y,i}),0):(Ans[i]=0);sort(S.begin(),S.end(),cmp);Solve(S,G,Id);for(i=1;i<=m;i++) printf("%d\n",Ans[i]); 
}
posted @ 2022-07-09 18:09  275307894a  阅读(33)  评论(0)    收藏  举报
浏览器标题切换
浏览器标题切换end