zoukankan      html  css  js  c++  java
  • POJ 3710:Christmas Game

    Description

    在树上挂几个环,每一个环只与树有一个公共点,环与环之间无公共边,每次删掉一条边,把不与根节点相连的部分删除,不能操作者输,问是否先手必胜。
    题面

    Solution

    由于环是在叶子上的,所以这个环可以单独考虑
    假设这个环是奇环,那么砍掉任意一条边之后,就会变成从叶子节点延伸出来的两条链,且这两条链奇偶性相同,所以后继状态的 (SG) 异或起来不可能为奇数,并且可以为 (0),所以 (SG=mex(SG[u])=1)
    假设这个环是偶环,那么这两条链的奇偶性不同,所以异或起来的所有情况中一定没有 (0),所以 (SG=mex=0)
    那么我们就可以把环缩成一个点了
    假设是偶环,实际上就没有贡献了,直接把它去掉就可以了
    假设是奇环,那么会有 (1) 的贡献,我们直接在这个叶子节点后面接上一个点就可以达到这样的效果了

    那么现在问题就转化为了树上删边游戏,利用结论:节点 (x)(SG) 等于所有儿子 (u)((SG[u]+1)) 的异或和
    这样就推出了根节点的 (SG)
    因为有很多棵树,再把所有根节点的 (SG) 异或起来就行了

    还有就是这个题仿佛是可以有点双的?

    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    using namespace std;
    const int N=2010;
    int n,m,T,sz[N],head[N],to[N*2],nxt[N*2],num=1;bool vis[N];
    int dfn[N],low[N],DFN=0,st[N],top=0,sum,q[N],r=0;
    inline void Clear(){
    	num=1;DFN=sum=0;
    	for(register int i=0;i<N;i++)sz[i]=head[i]=dfn[i]=low[i]=vis[i]=0;
    }
    inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
    inline void tarjan(int x,int last){
    	dfn[x]=low[x]=++DFN;st[++top]=x;
    	for(int i=head[x];i;i=nxt[i]){
    		if(i==last || to[i]>n)continue;
    		int u=to[i];
    		if(!dfn[u]){
    			tarjan(u,i^1),low[x]=min(low[x],low[u]);		
    			if(low[u]>=dfn[x]){
    				int sz=2;r=0;
    				while(top && st[top]!=u)q[++r]=st[top--],sz++;
    				if(top)q[++r]=st[top--];
    				if(sz>2)while(r)vis[q[r--]]=1;
    				if(sz>2 && (sz&1))link(x,++sum);
    			}
    		}
    		else low[x]=min(low[x],dfn[u]);
    	}
    }
    inline int dfs(int x,int last){
    	int ret=0;
    	for(int i=head[x];i;i=nxt[i]){
    		int u=to[i];
    		if(u==last || vis[u])continue;
    		ret^=(dfs(u,x)+1);
    	}
    	return ret;
    }
    inline int work(){
    	Clear();
    	int x,y;
    	scanf("%d%d",&n,&m);sum=n;
    	for(int i=1;i<=m;i++){
    		scanf("%d%d",&x,&y);
    		link(x,y);link(y,x);
    	}
    	tarjan(1,0);
    	return dfs(1,1);
    }
    int main(){
    	freopen("pp.in","r",stdin);
    	freopen("pp.out","w",stdout);
    	while(~scanf("%d",&T)){
    		int ans=0;
    		while(T--)ans^=work();
    		if(ans)puts("Sally");
    		else puts("Harry");
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    PHP 语法
    PHP 变量
    为什么说PHP是个集中营
    简单介绍ThinkPHP3.1.3使用笔记
    PHP实现提交表单及输出例子
    linux 用户组以及权限
    linux vim学习
    linux基础指令学习
    pycharm
    Codeforces Round #346 (Div. 2) C题
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8666926.html
Copyright © 2011-2022 走看看