[2020.11.13]CF704C Black Widow
题意
给出\(n\)个表达式,每个形如\(v_i\)或者\(v_i\or v_j\),\(v_i\)为布尔变量,\(-m\le i\le m\)且\(i\ne0\),其中\(v_{-i}=!v_i\),求使得共有奇数个式子值为真的\(v\)的取值的方案数。
保证\(v_{-i}\)和\(v_i\)在所有表达式中一共出现不超过\(2\)次。
题解
如果某个\(v_i\)出现了\(2\)次,就把它所在的两个表达式之间连一条边。
那么现在这个图应该形如若干条链和若干个环。可以对于每个环/链单独做。
对于链,可以从开头开始dp,记\(f_{i,j,k}\)表示考虑链上前\(i\)个式子,第\(i\)个式子和第\(i+1\)个式子之间的变量取值为\(j\),有\(k\)个式子为真的方案数。
对于环,可以枚举环上某个变量的取值,然后和链一样做。
最后把所有环和链的结果合并,注意特判没有出现的变量和形如\(v_i\or v_i\)或者\(v_i\or v_{-i}\)的式子即可。
code:
#include<bits/stdc++.h>
#define ci const int&
#define pi pair<int,int>
#define f first
#define s second
using namespace std;
const int mod=1e9+7;
int n,m,k[100010],v[100010][2],av[100010][2],ap[100010],in[100010][2],vis[100010],tg[100010],cnt;
pi ans,res[100010],dp[100010][2];
vector<int>lk[100010];
int Nx(ci x,ci y){
return in[x][in[x][0]==y];
}
void dfs(ci x,ci lv,vector<int>&l){
vis[x]=1,l.push_back(x);
if(av[x][0]!=lv)swap(av[x][0],av[x][1]),swap(v[x][0],v[x][1]);
if(ap[av[x][1]]==2)dfs(Nx(av[x][1],x),av[x][1],l);
}
void dfs2(ci x,ci lv,ci sv,vector<int>&l){
vis[x]=1,l.push_back(x);
if(av[x][0]!=lv)swap(av[x][0],av[x][1]),swap(v[x][0],v[x][1]);
if(av[x][1]!=sv)dfs2(Nx(av[x][1],x),av[x][1],sv,l);
}
pi op(pi x,pi y){
return(pi){(1ll*x.f*y.f+1ll*x.s*y.s)%mod,(1ll*x.f*y.s+1ll*x.s*y.f)%mod};
}
int val(ci x,ci v1,ci v2){
return (v1^(v[x][0]<0))|(v2^(v[x][1]<0));
}
void Add(int&x,ci y){
(x+=y)>=mod?x-=mod:0;
}
pi Calc(ci x){
if(!tg[x]){
dp[0][0].f=1,dp[0][1].f=(k[lk[x][0]]==2),dp[0][0].s=dp[0][1].s=0;
for(int i=0;i<lk[x].size();++i){
dp[i+1][0]=dp[i+1][1]=(pi){0,0};
if(val(lk[x][i],0,0))Add(dp[i+1][0].f,dp[i][0].s),Add(dp[i+1][0].s,dp[i][0].f);
else Add(dp[i+1][0].f,dp[i][0].f),Add(dp[i+1][0].s,dp[i][0].s);
if(val(lk[x][i],1,0))Add(dp[i+1][0].f,dp[i][1].s),Add(dp[i+1][0].s,dp[i][1].f);
else Add(dp[i+1][0].f,dp[i][1].f),Add(dp[i+1][0].s,dp[i][1].s);
if(i!=lk[x].size()-1||k[lk[x][lk[x].size()-1]]==2){
if(val(lk[x][i],0,1))Add(dp[i+1][1].f,dp[i][0].s),Add(dp[i+1][1].s,dp[i][0].f);
else Add(dp[i+1][1].f,dp[i][0].f),Add(dp[i+1][1].s,dp[i][0].s);
if(val(lk[x][i],1,1))Add(dp[i+1][1].f,dp[i][1].s),Add(dp[i+1][1].s,dp[i][1].f);
else Add(dp[i+1][1].f,dp[i][1].f),Add(dp[i+1][1].s,dp[i][1].s);
}
}
return(pi){(dp[lk[x].size()][0].f+dp[lk[x].size()][1].f)%mod,(dp[lk[x].size()][0].s+dp[lk[x].size()][1].s)%mod};
}else{
pi ret;
dp[0][0].f=1,dp[0][1].f=dp[0][0].s=dp[0][1].s=0;
for(int i=0;i<lk[x].size();++i){
dp[i+1][0]=dp[i+1][1]=(pi){0,0};
if(val(lk[x][i],0,0))Add(dp[i+1][0].f,dp[i][0].s),Add(dp[i+1][0].s,dp[i][0].f);
else Add(dp[i+1][0].f,dp[i][0].f),Add(dp[i+1][0].s,dp[i][0].s);
if(val(lk[x][i],1,0))Add(dp[i+1][0].f,dp[i][1].s),Add(dp[i+1][0].s,dp[i][1].f);
else Add(dp[i+1][0].f,dp[i][1].f),Add(dp[i+1][0].s,dp[i][1].s);
if(i!=lk[x].size()-1){
if(val(lk[x][i],0,1))Add(dp[i+1][1].f,dp[i][0].s),Add(dp[i+1][1].s,dp[i][0].f);
else Add(dp[i+1][1].f,dp[i][0].f),Add(dp[i+1][1].s,dp[i][0].s);
if(val(lk[x][i],1,1))Add(dp[i+1][1].f,dp[i][1].s),Add(dp[i+1][1].s,dp[i][1].f);
else Add(dp[i+1][1].f,dp[i][1].f),Add(dp[i+1][1].s,dp[i][1].s);
}
}
ret=(pi){dp[lk[x].size()][0].f+dp[lk[x].size()][1].f,dp[lk[x].size()][0].s+dp[lk[x].size()][1].s};
dp[0][1].f=1,dp[0][0].f=dp[0][0].s=dp[0][1].s=0;
for(int i=0;i<lk[x].size();++i){
dp[i+1][0]=dp[i+1][1]=(pi){0,0};
if(i!=lk[x].size()-1){
if(val(lk[x][i],0,0))Add(dp[i+1][0].f,dp[i][0].s),Add(dp[i+1][0].s,dp[i][0].f);
else Add(dp[i+1][0].f,dp[i][0].f),Add(dp[i+1][0].s,dp[i][0].s);
if(val(lk[x][i],1,0))Add(dp[i+1][0].f,dp[i][1].s),Add(dp[i+1][0].s,dp[i][1].f);
else Add(dp[i+1][0].f,dp[i][1].f),Add(dp[i+1][0].s,dp[i][1].s);
}
if(val(lk[x][i],0,1))Add(dp[i+1][1].f,dp[i][0].s),Add(dp[i+1][1].s,dp[i][0].f);
else Add(dp[i+1][1].f,dp[i][0].f),Add(dp[i+1][1].s,dp[i][0].s);
if(val(lk[x][i],1,1))Add(dp[i+1][1].f,dp[i][1].s),Add(dp[i+1][1].s,dp[i][1].f);
else Add(dp[i+1][1].f,dp[i][1].f),Add(dp[i+1][1].s,dp[i][1].s);
}
return(pi){(1ll*ret.f+dp[lk[x].size()][0].f+dp[lk[x].size()][1].f)%mod,(1ll*ret.s+dp[lk[x].size()][0].s+dp[lk[x].size()][1].s)%mod};
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
scanf("%d",&k[i]);
for(int j=0;j<k[i];++j)scanf("%d",&v[i][j]),av[i][j]=abs(v[i][j]),in[av[i][j]][ap[av[i][j]]++]=i;
}
for(int i=1;i<=n;++i)if(!vis[i]){
if(k[i]==1&&ap[av[i][0]]==1)vis[i]=1,res[++cnt].f=1,res[cnt].s=1;
else if(av[i][0]==av[i][1])vis[i]=1,res[++cnt].s=1+(v[i][0]!=v[i][1]),res[cnt].f=2-res[cnt].s;
else if((ap[av[i][0]]==2)+(ap[av[i][1]]==2)!=2){
vis[i]=1;
if(ap[av[i][0]]==2)swap(av[i][0],av[i][1]),swap(v[i][0],v[i][1]);
if(ap[av[i][1]]==2)++cnt,dfs(i,av[i][0],lk[cnt]);
else res[++cnt].f=1,res[cnt].s=3;
}
}
for(int i=1;i<=n;++i)if(!vis[i])tg[++cnt]=1,lk[cnt].push_back(i),dfs2(Nx(av[i][1],i),av[i][1],av[i][0],lk[cnt]);
ans.f=1;
for(int i=1;i<=cnt;++i){
if(!res[i].s)res[i]=Calc(i);
ans=op(ans,res[i]);
}
for(int i=1;i<=m;++i)if(!ap[i])(ans.s<<=1)>=mod?ans.s-=mod:0;
printf("%d",ans.s);
return 0;
}