• 【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;
    }
    
  • 相关阅读:
    练习10.9-2
    [转]JVM 内存初学 (堆(heap)、栈(stack)和方法区(method) )
    JAVA成员变量为什么不能在类体中先定义后赋值
    core image几个滤镜样例 oc版本号和swift版本号
    UVa 11997 K Smallest Sums 优先队列&amp;&amp;打有序表&amp;&amp;归并
    Android基础新手教程——4.4.1 ContentProvider初探
    Restore IP Addresses -- LeetCode
    Android中Intent传递类对象的方法一(Serializable)
    Effective C++:条款22:将成员变量声明为private
    javascript cookie
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10409134.html
Copyright © 2020-2023  润新知