zoukankan      html  css  js  c++  java
  • 【BZOJ5303】[HAOI2018]反色游戏(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;
    }
    
  • 相关阅读:
    19. 星际争霸之php设计模式--迭代器模式
    18. 星际争霸之php设计模式--观察者模式
    17. 星际争霸之php设计模式--职责链模式
    16. 星际争霸之php设计模式--组合模式
    15. 星际争霸之php设计模式--策略模式
    14. 星际争霸之php设计模式--状态模式
    13. 星际争霸之php设计模式--正面模式
    12. 星际争霸之php设计模式--模板模式
    11. 星际争霸之php设计模式--备忘模式
    10. 星际争霸之php设计模式--原型模式
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10409134.html
Copyright © 2011-2022 走看看