Description
n,m<=10^5
Solution
考虑图论转化,既然每个变量最多只会出现两次,那么我们把出现两次的变量所在的or组看做点,每个出现两次的变量看做边,边权视这两个变量是否相同而定。(0或1)
根据题目条件我们每个点的度数最多为2,也就是只会出现环和链。
设Fi,j,k表示当前做到第i个点,异或值为j,上一位填的是k的方案数,转移显然。
最后分类讨论一下就行了,注意特判自环和没有出现的点。
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define rep(i,a) for(int i=last[a];i;i=next[i])
using namespace std;
typedef long long ll;
const int N=1e5+5,mo=1e9+7;
int n,m,l,x,y,ans,a[N][2],r[N],p[N],w[N];
int t[N*2],next[N*2],v[N*2],one[N],last[N];
int f[N][2][2],now[2],s[2],la[2];
bool bz[N];
void add(int x,int y,int z) {
t[++l]=y;v[l]=z;next[l]=last[x];last[x]=l;
}
void dfs(int x,int y) {
if (bz[x]) return;
bz[x]=1;w[++w[0]]=x;
rep(i,x)
if (t[i]!=y) {
p[++p[0]]=v[i];
dfs(t[i],x);
}
}
void dp_chain() {
memset(f[1],0,sizeof(f[1]));
if (one[w[1]]) f[1][1][1]=2,f[1][1][0]=f[1][0][0]=1;
else f[1][1][1]=f[1][0][0]=1;
fo(i,1,w[0]-1) {
fo(j,0,1)
fo(k,0,1)
f[i+1][j][k]=0;
fo(j,0,1)
fo(k,0,1)
if (f[i][j][k])
fo(l,0,1)
(f[i+1][j^(l|(p[i]^k))][l]+=f[i][j][k])%=mo;
}
s[0]=s[1]=0;
la[0]=now[0];la[1]=now[1];
if (one[w[w[0]]]) {
fo(i,0,1)
fo(j,0,1)
(s[i]+=f[w[0]][i][j])%=mo;
} else fo(i,0,1) s[i]=f[w[0]][i][0];
now[0]=((ll)la[0]*s[0]%mo+(ll)la[1]*s[1]%mo)%mo;
now[1]=((ll)la[0]*s[1]%mo+(ll)la[1]*s[0]%mo)%mo;
}
void dp_circle() {
s[0]=s[1]=0;
la[0]=now[0];la[1]=now[1];
if (w[0]==1) {
if (p[0]) s[p[1]]=2;
else {
if (one[w[1]]==1) s[0]=s[1]=1;
else s[0]=1,s[1]=3;
}
now[0]=((ll)la[0]*s[0]%mo+(ll)la[1]*s[1]%mo)%mo;
now[1]=((ll)la[0]*s[1]%mo+(ll)la[1]*s[0]%mo)%mo;
return;
}
fo(st,0,1) {
memset(f[1],0,sizeof(f[1]));
if (st) f[1][1][0]=f[1][1][1]=1;
else f[1][0][0]=f[1][1][1]=1;
fo(i,1,w[0]-1) {
fo(j,0,1)
fo(k,0,1)
f[i+1][j][k]=0;
fo(j,0,1)
fo(k,0,1)
if (f[i][j][k])
fo(l,0,1)
(f[i+1][j^(l|(p[i]^k))][l]+=f[i][j][k])%=mo;
}
int en=st^p[p[0]];
fo(i,0,1) (s[i]+=f[w[0]][i][en])%=mo;
}
now[0]=((ll)la[0]*s[0]%mo+(ll)la[1]*s[1]%mo)%mo;
now[1]=((ll)la[0]*s[1]%mo+(ll)la[1]*s[0]%mo)%mo;
}
int main() {
freopen("equation.in","r",stdin);
freopen("equation.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,n)
for(scanf("%d",&y);y;y--) {
scanf("%d",&x);
if (!a[abs(x)][0]) a[abs(x)][0]=i*((x>0)?1:-1);
else a[abs(x)][1]=i*((x>0)?1:-1);
}
ans=now[0]=1;
fo(i,1,m) {
if (!a[i][0]) {ans=ans*2%mo;continue;}
if (!a[i][1]) {one[abs(a[i][0])]++;continue;}
int x=a[i][0],y=a[i][1],z=x<0&&y>0||x>0&&y<0;
add(abs(x),abs(y),z);add(abs(y),abs(x),z);
r[abs(x)]++;r[abs(y)]++;
}
fo(i,1,n)
if (r[i]==1&&!bz[i]) {
p[0]=w[0]=0;
dfs(i,0);
dp_chain();
}
fo(i,1,n)
if (!bz[i]) {
p[0]=w[0]=0;
dfs(i,0);
dp_circle();
}
printf("%lld\n",(ll)ans*now[1]%mo);
}