首页 > 其他 > 详细

【BZOJ5303】[HAOI2018]反色游戏(Tarjan,线性基)

时间:2019-02-20 21:01:54      阅读:198      评论:0      收藏:0      [点我收藏+]

【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,线性基)

原文:https://www.cnblogs.com/cjyyb/p/10409134.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!