【BZOJ5303】[HAOI2018]反色遊戲(Tarjan,線性基)
阿新 • • 發佈:2019-02-20
truct span 通過 new com tchar 情況 lse tarjan
那麽\(Tarjan\)做一遍計算一下需要的信息就好了。
【BZOJ5303】[HAOI2018]反色遊戲(Tarjan,線性基)
題面
BZOJ
洛谷
題解
把所有點全部看成一個\(01\)串,那麽每次選擇一條邊意味著在這個\(01\)串的基礎上異或上一個有\(2\)個\(1\)的\(01\)串。
那麽把邊構建線性基,最終的答案顯然就是\(2\)的不在線性基裏的邊數次方。
顯然每次只需要考慮一個聯通塊,一個聯通塊隨便拉出一棵生成樹,就可以在線性基上確定\(n-1\)個元,那麽對於其他邊任意的情況,顯然可以通過修改這\(n-1\)條邊的選擇情況使得最終滿足條件,因此此時方案數是\(2^{m-n+1}\)。考慮如果一個聯通塊有解,那麽黑點的個數必定為偶數個,這樣子可以任意兩兩配對之後取反路徑上的所有邊,否則為奇數個無法配對,必定無解。
#include<iostream> #include<cstdio> using namespace std; #define MAX 100100 #define MOD 1000000007 inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } struct Line{int v,next;}e[MAX<<1]; int h[MAX],cnt=1,dg[MAX]; inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;++dg[u];} int n,m,a[MAX],bin[MAX<<1];char ch[MAX]; int dfn[MAX],low[MAX],vis[MAX],tim,rt; int sum[MAX],c[MAX],d[MAX],f[MAX]; void init() { cnt=1;tim=0; for(int i=1;i<=n;++i)h[i]=dfn[i]=low[i]=dg[i]=d[i]=c[i]=f[i]=0; } void Tarjan(int u) { dfn[u]=low[u]=++tim;vis[u]=rt;sum[u]=a[u]; for(int i=h[u];i;i=e[i].next) { int v=e[i].v; if(!dfn[v]) { Tarjan(v);sum[u]+=sum[v]; low[u]=min(low[u],low[v]); if(low[v]>=dfn[u])d[u]|=(sum[v]&1),c[u]+=1,f[u]+=sum[v]; } else low[u]=min(low[u],dfn[v]); } if(u==rt)c[u]-=1; } int main() { bin[0]=1;for(int i=1;i<MAX<<1;++i)bin[i]=(bin[i-1]<<1)%MOD; int T=read(); while(T--) { n=read();m=read();init();int val=0,tot=0; for(int i=1,u,v;i<=m;++i)u=read(),v=read(),Add(u,v),Add(v,u); scanf("%s",ch+1);for(int i=1;i<=n;++i)a[i]=ch[i]-48; for(int i=1;i<=n;++i)if(!dfn[i])rt=i,Tarjan(i),++tot,val+=sum[i]&1; printf("%d ",val?0:bin[m-n+tot]); for(int i=1;i<=n;++i) if(d[i])printf("0 "); else if(val-(sum[vis[i]]&1))printf("0 "); else if((sum[vis[i]]-a[i]-f[i])&1)printf("0 "); else printf("%d ",bin[m-n+tot-dg[i]+1+c[i]]); puts(""); } return 0; }
【BZOJ5303】[HAOI2018]反色遊戲(Tarjan,線性基)