P4494 [HAOI2018]反色游戏
解题方法:
先考虑一个经典问题:
对于一颗全部是白色节点的树,要求将某些节点染成黑色,且每一次染色操作为任选一边将两端点染成与其原来颜色相反的颜色,求方案数
容易推得,当黑色节点数为奇数个时,方案数为0,即无解;黑色节点为偶数个时,方案数为1
那么把问题放到图上时,我们发现我们只要随机搞出来一颗生成树,然后随机选择这个连通图上非树边
若无解的话无论怎么选择都无解,若有解的话怎么选择都有解
方案数显然为$2^{m-n+1}$
由于可能出现图数不为1的情况,而每多一张图,非树边就会增加一条,所以答案就为$2^{m-n+图数}$
对于删点,我们对其分类讨论:
1.为独立点
2.不是割点
3.是割点
然后进行求解即可
#include<bits/stdc++.h> #define maxn 100005 #define maxm 500005 #define inf 0x7fffffff #define ll long long #define rint register int #define debug(x) cerr<<#x<<": "<<x<<endl #define fgx cerr<<"--------------"<<endl #define rep(i,a,b) for(int i=a;i<=b;i++) #define dgx cerr<<"=============="<<endl #define lowbit(x) (x&(-x)) #define MAXN 100005 using namespace std; const ll mod=1e9+7; inline int read(){ int x=0,f=1; char ch=getchar(); while('0'>ch || ch>'9'){if(ch=='-') f=-1; ch=getchar();} while('0'<=ch && ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();} return x*f; } int T,fir[MAXN],to[MAXN<<1],nxt[MAXN<<1],tot,a[MAXN],n,m,book[MAXN],maps,de[MAXN]; int ind[MAXN],dfn[MAXN],num,cnt,col[MAXN],mp[MAXN],totl,p[MAXN],low[MAXN]; void ade(int x,int y){ to[++tot]=y; nxt[tot]=fir[x]; fir[x]=tot; de[y]++; } void init(){ memset(fir,0,sizeof(fir)); tot=0; memset(book,0,sizeof(book)); memset(ind,0,sizeof(ind)); memset(dfn,0,sizeof(dfn)); memset(de,0,sizeof(de)); memset(p,0,sizeof(p)); maps=0; cnt=0; totl=0; } void Tarjan(int x,int y){ mp[cnt]^=a[x]; col[x]=cnt; dfn[x]=low[x]=++num; int son=0,qq; for(int k=fir[x];k;k=nxt[k]){ if(!dfn[to[k]]){ qq=mp[cnt]; Tarjan(to[k],0); low[x]=min(low[x],low[to[k]]); if(low[to[k]]>=dfn[x]){ son++; if(!y) book[x]=son+1; else if(son>=2) book[x]=son; p[x]=p[x]+(qq^mp[cnt]); } } else low[x]=min(low[x],dfn[to[k]]); } } ll ksm(ll x,ll y){ ll res=1; while(y){ if(y&1) res=(res*x)%mod; x=(x*x)%mod; y>>=1; } return res; } int main(){ T=read(); while(T--){ init(); n=read(); m=read(); // cin>>n>>m; // cout<<"GG"<<n<<" "<<m<<endl; rep(i,1,m){ int x=read(),y=read(); ade(x,y); ade(y,x); } char ch=getchar(); rep(i,1,n){ while(ch!='0' && ch!='1') ch=getchar(); a[i]=ch-'0'; ch=getchar(); } // rep(i,1,n) cout<<a[i]<<" " ;cout<<endl; rep(i,1,n){ if(!dfn[i]){ mp[++cnt]=0,Tarjan(i,1); if(mp[cnt]) ++totl; if(!fir[i]) ind[i]=1; } } // rep(i,1,n) cout<<book[i]<<" ";cout<<endl; if(!totl) printf("%lld ",ksm(2,m-n+cnt)); else printf("0 "); rep(i,1,n){ if(totl>1){printf("0 ");continue;} if(ind[i]){ if(!totl) printf("%lld ",ksm(2,m-n+cnt)); else printf("0 "); } else if(!book[i]){ if((mp[col[i]] && a[i]) || (!mp[col[i]] && !a[i] && !totl)) printf("%lld ",ksm(2,(m-de[i])-(n-1)+cnt)); else printf("0 "); } else{ if(mp[col[i]]^a[i] || (!mp[col[i]] && totl)){printf("0 "); continue;} if(p[i]) printf("0 "); else printf("%lld ",ksm(2,(m-de[i])-(n-1)+(cnt+book[i]-1))); } } cout<<endl; } return 0; }