Codeforces 461D. Appleman and Complicated Task 构造,计数

原文链接https://www.cnblogs.com/zhouzhendong/p/CF461D.html

题解

首先我们可以发现如果确定了第一行,那么方案就唯一了。

然后,我们来看看一个点的值确定了会导致什么:

假设我们确定了红色点的值,那么所有包含橙色的格子xor起来就等于红色格子的值,绿色蓝色也是。

第一排就比较特殊了。

如果我们在对第一排奇偶分类之后,如果我们可以得到第一行的前缀xor之间的关系,那么我们就有希望解决这个问题。

再看一种情况:

类似地意思,我们会发现这个东西遇到墙会反射。

于是我们就基本可以通过权值并查集来搞定。

我们还剩下一个问题:

这样的方式还不能确定最下面一行是否满足条件。

我们来看一个东西:

通过这个我们可以意识到,第一行和最后一行是一一对应的。于是整个局面旋转180度还是一样的。于是只要第一行合法,那么最后一行也合法。

所以我们只要通过给出的点用权值并查集维护一下第一行,然后算一下答案就好了。

代码

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof (x))
#define For(i,a,b) for (int i=a;i<=b;i++)
#define Fod(i,b,a) for (int i=b;i>=a;i--)
using namespace std;
typedef long long LL;
LL read(){
	LL x=0,f=0;
	char ch=getchar();
	while (!isdigit(ch))
		f|=ch=='-',ch=getchar();
	while (isdigit(ch))
		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return f?-x:x;
}
const int N=100005,mod=1e9+7;
int n,k;
int fa[N],d[N];
int getf(int x){
	if (fa[x]==x)
		return x;
	int f=getf(fa[x]);
	d[x]^=d[fa[x]];
	return fa[x]=f;
}
int Pow(int x,int y){
	int ans=1;
	for (;y;y>>=1,x=(LL)x*x%mod)
		if (y&1)
			ans=(LL)ans*x%mod;
	return ans;
}
int main(){
	n=read(),k=read();
	For(i,0,n)
		fa[i]=i;
	while (k--){
		int x=read(),y=read(),z;
		char s[10];
		scanf("%s",s);
		z=s[0]=='x'?0:1;
		int L=y-(x-1);
		if (L<1)
			L=1+(1-L);
		int R=y+(x-1);
		if (R>n)
			R=n-(R-n);
		L=max(0,L-2);
		if (getf(L)!=getf(R))
			d[fa[L]]=z^d[L]^d[R],fa[fa[L]]=fa[R];
		else if (d[L]^d[R]^z)
			return puts("0"),0;
	}
	int ans=-1;
	For(i,0,n)
		if (fa[i]==i)
			ans++;
	if (ans==-1)
		assert(0);
	cout<<Pow(2,ans)<<endl;
	return 0;
}

  

posted @ 2019-03-02 15:01  zzd233  阅读(358)  评论(0编辑  收藏  举报