zoukankan      html  css  js  c++  java
  • BZOJ5303: [Haoi2018]反色游戏

    BZOJ5303: [Haoi2018]反色游戏

    https://lydsy.com/JudgeOnline/problem.php?id=5303

    分析:

    • 如果(1)的个数为奇数,肯定无解。
    • 否则,如果是一棵树,答案为(1)
    • 否则,多出的那些边不会影响答案,答案为(2^{n-m-1})
    • 若干个连通块需要乘起来,设连通块有(tot)个,那么答案就是(2^{n-m-tot})
    • 分析删点后的影响。
      1. 孤立点,由于会被当做非割点需要单独拿出来特判。
      1. 非割点,没啥可说的,直接用公式计算即可。
      1. 割点,由于删去后需要重新计算连通块数和每个连通块内(1)的个数,我这里用圆方树来处理每个割点,在圆方树上可能会比较好理解,在原图上删掉这个点和在圆方树上删掉这个点是等价的。
    • 具体实现看代码,代码写的比较恶心。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    #include <vector>
    using namespace std;
    #define N 200050
    #define mod 1000000007
    #define mem(x) memset(x,0,sizeof(x))
    typedef long long ll;
    vector<int>V[N];
    int head[N],to[N<<1],nxt[N<<1],cnt,n,m;
    int dfn[N],low[N],S[N<<1],tp,vis[N<<1],bl[N],iscut[N],du[N],bcc,fa[N],tot,siz[N],se[N],sw[N];
    char w[N];
    ll totans,tans[N],ans[N],mi[N];
    ll qp(ll x,ll y) {
    	ll re=1;for(;y;y>>=1,x=x*x%mod) if(y&1) re=re*x%mod; return re;
    }
    inline void add(int u,int v) {
    	to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
    }
    void tarjan(int x,int rt) {
    	int i,num=0;
    	fa[x]=tot;
    	siz[tot]++;
    	sw[tot]+=(w[x]=='1');
    	dfn[x]=low[x]=++dfn[0];
    	for(i=head[x];i;i=nxt[i]) if(!vis[i]) {
    		S[++tp]=i;
    		num++;
    		se[tot]++;
    		vis[i]=vis[i^1]=1;
    		if(!dfn[to[i]]) {
    			tarjan(to[i],x);
    			low[x]=min(low[x],low[to[i]]);
    			if(low[to[i]]>=dfn[x]) {
    				bcc++; V[bcc].clear();
    				int t=0;
    				iscut[x]=1;
    				while(t!=i) {
    					t=S[tp--];
    					int u=to[t], v=to[t^1];
    					if(bl[u]!=bcc) bl[u]=bcc,V[bcc].push_back(u);
    					if(bl[v]!=bcc) bl[v]=bcc,V[bcc].push_back(v);
    				}
    			}
    		}else low[x]=min(low[x],dfn[to[i]]);
    	}
    	if(x==rt&&num<2) iscut[rt]=0;
    }
    int hme,flg[N],TOT;
    void dfs(int x,int y) {
    	int i,cc=0; vis[x]=1;
    	if(x<=n) siz[x]=w[x]=='1';
    	else siz[x]=0;
    	for(i=head[x];i;i=nxt[i]) if(to[i]!=y) {
    		dfs(to[i],x);
    		siz[x]+=siz[to[i]];
    		if(siz[to[i]]&1) {
    			flg[x]=1;
    		}
    		cc++;
    	}
    	if(x>n) return ;
    	if(y) cc++;
    	if((sw[fa[x]]-siz[x])&1) flg[x]=1;
    	if(hme-(sw[fa[x]]&1)>0) flg[x]=1;
    	if(iscut[x]) {
    		if(flg[x]) ans[x]=0;
    		else {
    			ans[x]=mi[m-du[x]-n+1+cc+tot-1];
    		}
    	}
    }
    void solve() {
    	memset(head,0,sizeof(head)); cnt=1;
    	memset(dfn,0,sizeof(dfn));
    	memset(vis,0,sizeof(vis));
    	memset(bl,0,sizeof(bl));
    	memset(iscut,0,sizeof(iscut));
    	bcc=0;
    	memset(siz,0,sizeof(siz));
    	memset(se,0,sizeof(se));
    	memset(sw,0,sizeof(sw));
    	memset(du,0,sizeof(du));
    	memset(flg,0,sizeof(flg));
    	mem(fa);
    	TOT=0; tot=0; tp=0; hme=0;
    	scanf("%d%d",&n,&m);
    	int i,x,y,j;
    	int lm=max(n,m);
    	for(mi[0]=i=1;i<=lm;i++) mi[i]=mi[i-1]*2%mod;
    	for(i=1;i<=m;i++) {
    		scanf("%d%d",&x,&y);
    		add(x,y); add(y,x); du[x]++; du[y]++;
    	}
    	scanf("%s",w+1);
    	for(i=1;i<=n;i++) if(!dfn[i]) {
    		tot++; tarjan(i,i);
    	}
    	totans=1;
    	for(i=1;i<=tot;i++) {
    		if(sw[i]&1) tans[i]=0,hme++;
    		else {
    			tans[i]=mi[se[i]-siz[i]+1];
    			totans=totans*tans[i]%mod;
    		}
    	}
    	if(hme) ans[0]=0;
    	else ans[0]=totans;
    	for(x=1;x<=n;x++) {
    		if(siz[fa[x]]==1) {
    			if(hme-(sw[fa[x]]&1)>0) ans[x]=0;
    			else ans[x]=totans;
    			continue;
    		}
    		if(!iscut[x]) {
    			if(hme-(sw[fa[x]]&1)>0) ans[x]=0;
    			else if((sw[fa[x]]-(w[x]=='1'))&1) ans[x]=0;
    			else ans[x]=mi[m-du[x]-n+1+tot];
    		}
    	}
    	memset(head,0,sizeof(head)); cnt=0;
    	for(i=1;i<=bcc;i++) {
    		int lim=V[i].size();
    		for(j=0;j<lim;j++) {
    			add(V[i][j],i+n);
    			add(i+n,V[i][j]);
    		}
    	}
    	memset(siz,0,sizeof(siz));
    	mem(vis);
    	int ln=n+bcc;
    	for(i=1;i<=n;i++) TOT+=w[i]=='1';
    	for(i=1;i<=ln;i++) if(!vis[i]) {
    		dfs(i,0);
    	}
    	for(i=0;i<=n;i++) printf("%lld ",ans[i]); puts("");
    }
    int main() {
    	int T;
    	scanf("%d",&T);
    	while(T--) solve();
    }
    
  • 相关阅读:
    sql语句中in和exists的区别
    springboot整合kafka
    多线程基础(三)线程通信
    多线程基础(四)线程控制
    多线程基础(二)线程状态
    创建计算字段
    MySQL学习之正则表达式篇
    response没有实现跳转,而是提示浏览器下载文件
    AJAX简述
    四大作用域
  • 原文地址:https://www.cnblogs.com/suika/p/10230160.html
Copyright © 2011-2022 走看看