Descritpion
Solution
这题和之前没改出来的矩阵游走思想是类似的,即唯一确定的第一行确定了整个矩阵。那么可以设第一行为未知数,讨论一下其余位置的取值情况。可以发现(0,k)能影响到的点满足是连续的奇数或连续的偶数。那么抽出奇偶点然后就能用前缀异或和做了。
题目转化为:给定一些限制条件形如sum[l-1]^sum[r]=0或1,求可行方案数
可以回想2sat的做法,把点i拆为i和i’表示i取0或1,讨论一下并查集合并判无解就ok
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stdlib.h>
#include <time.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
typedef long long LL;
const int MOD=1000000007;
const int N=200005;
int fa[N],a[N],b[N];
LL ksm(LL x,LL dep) {
if (dep==0) return 1;
if (dep==1) return x;
LL tmp=ksm(x,dep/2);
if (dep%2) return tmp*tmp%MOD*x%MOD;
return tmp*tmp%MOD;
}
int get_father(int now) {
return (fa[now]==-1)?(now):(fa[now]=get_father(fa[now]));
}
bool merge(int x,int y) {
x=get_father(x); y=get_father(y);
if (x==get_father(x^1)) return false;
if (y==get_father(y^1)) return false;
if (x!=y) fa[x]=y;
return true;
}
bool check(int x,int y,int z) {
if (z==0) {
return merge(x*2,y*2)&&merge(x*2+1,y*2+1);
} else if (z==1) {
return merge(x*2,y*2+1)&&merge(x*2+1,y*2);
}
}
int main(void) {
fill(fa,-1);
int n,m; scanf("%d%d",&n,&m);
rep(i,1,m) {
int x,y; scanf("%d%d",&x,&y);
x-=1; y-=1;
char ch[2]; scanf("%s",ch);
int l=std:: abs(x-y);
int r=std:: min(x+y,2*(n-1)-(x+y));
if (!check(l,r+2,ch[0]=='o')) {
puts("0");
return 0;
}
}
LL ans=0;
rep(i,0,n*2+3) if (get_father(i)==i) ans++;
LL prt=ksm(2,ans/2-2);
printf("%lld\n", prt);
return 0;
}