zoukankan      html  css  js  c++  java
  • [2020.11.13]CF704C Black Widow

    题意

    给出(n)个表达式,每个形如(v_i)或者(v_ior v_j)(v_i)为布尔变量,(-mle ile m)(i e0),其中(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_ior v_i)或者(v_ior 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;
    }
    
  • 相关阅读:
    CodeForces 219D Choosing Capital for Treeland (树形DP)
    POJ 3162 Walking Race (树的直径,单调队列)
    POJ 2152 Fire (树形DP,经典)
    POJ 1741 Tree (树的分治,树的重心)
    POJ 1655 Balancing Act (树的重心,常规)
    HDU 2196 Computer (树形DP)
    HDU 1520 Anniversary party (树形DP,入门)
    寒门子弟
    JQuery选择器(转)
    (四)Web应用开发---系统架构图
  • 原文地址:https://www.cnblogs.com/xryjr233/p/CF704C.html
Copyright © 2011-2022 走看看