1. 程式人生 > >【BZOJ5303】[HAOI2018]反色遊戲(Tarjan,線性基)

【BZOJ5303】[HAOI2018]反色遊戲(Tarjan,線性基)

truct span 通過 new com tchar 情況 lse tarjan

【BZOJ5303】[HAOI2018]反色遊戲(Tarjan,線性基)

題面

BZOJ
洛谷

題解

把所有點全部看成一個\(01\)串,那麽每次選擇一條邊意味著在這個\(01\)串的基礎上異或上一個有\(2\)\(1\)\(01\)串。
那麽把邊構建線性基,最終的答案顯然就是\(2\)的不在線性基裏的邊數次方。
顯然每次只需要考慮一個聯通塊,一個聯通塊隨便拉出一棵生成樹,就可以在線性基上確定\(n-1\)個元,那麽對於其他邊任意的情況,顯然可以通過修改這\(n-1\)條邊的選擇情況使得最終滿足條件,因此此時方案數是\(2^{m-n+1}\)。考慮如果一個聯通塊有解,那麽黑點的個數必定為偶數個,這樣子可以任意兩兩配對之後取反路徑上的所有邊,否則為奇數個無法配對,必定無解。

那麽\(Tarjan\)做一遍計算一下需要的信息就好了。

#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,線性基)