zoukankan      html  css  js  c++  java
  • xsy1436-括号游戏

    题目

    递归定义括号序列

    • 空串是括号序列
    • (A)是一个括号序列,其中A为括号序列
    • AB是一个括号序列,其中A,B均为括号序列
      定义严格括号序列为形如(A)的括号序列,其中A为括号序列。

    给出一个长度为(n(nle 10^3))的合法括号序列,两个人进行游戏,每次一个人取走一个严格括号序列,不能再取的算输,问先手必胜还是后手必胜。

    分析

    好题。严格括号序列可以看成一棵树。一个严格括号序列的每个左括号表示一个点深搜进入,右括号表示遍历完所有的子树了。一个不严格的括号序列可以看成一堆树,就是一个森林。这个游戏完全等价于在一个森林中轮流删除一个点及其子树。这是一个经典问题。

    Green Hackenbush Game

    砍树游戏是指,在一个有根树组成的森林中,两个玩家轮流砍掉树上的一条边,那条边连出去的子树都被砍掉。无法操作者输。

    如何考察这个问题?首先考虑最简单的形式,所有的有根树都是一条,那么这个问题就完全等价于一个Nim游戏,因为每一次都是在一棵树上的(n)个点中删去(ain [1,n])个点,相当于在许多堆石子中每次选一堆,取出任意多个。从SG函数的角度看,对于一条链,它的SG值其实就是链的长度。

    接下来考虑如何把一颗分叉的树转化为链的形式。

    Colon Principle

    对于树上的一个分叉的节点,所有的分叉都是一条链,那么可以把这些分叉换成一条长度为它们异或和的链,新树与原树在游戏中等价。

    有了这个性质,我们只要自下而上把所有的分叉换成链,到最后整棵树形成一条链,我们就得到整棵树的SG值了。

    下面我们来证明这个性质。

    有两颗随机的树(H_1,H_2),满足它们的SG函数值是相同的。现在有一棵树(G)和上面一个定点(x),用(G_1)表示把(H_1)接在(G)(x)点上形成的树,(G_2)表示把(H_2)接在(G)(x)点上形成的树。我们现在要证明的就是,这两棵树根节点的SG函数值是相同的。这其实就是在证明两棵树的根节点的SG值异或为0。由于多个子游戏拼成的大游戏的SG值就是每个子游戏的SG值异或起来,所以这个证明等价于把这两棵树放在一起做游戏,规则是每次砍掉任意一棵树的任意一条边,后手必胜。一种显然的后手必胜方法就是,对于不涉及到(H)内部的操作,后手模仿先手的操作,因为两棵树除了(H)的部分是完全一样的。对于涉及到(H)内部的操作,即只涉及子树内的操作,我们可以看成是(H_1)(H_2)单独做游戏。由于(H_1)(H_2)的SG函数值是一样的,所以这两颗树的单独游戏也是后手必胜的。这样整个游戏就是后手必胜的了,故结论成立。

    非常巧妙的构造和证明!

    代码

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    using namespace std;
    int read() {
    	int x=0,f=1;
    	char c=getchar();
    	for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
    	for (;isdigit(c);c=getchar()) x=x*10+c-'0';
    	return x*f;
    }
    const int maxn=1e3+1;
    char s[maxn];
    int sta[maxn],top,n,tim=0,ck[maxn];
    struct edge {
    	int v,nxt;
    } e[maxn<<1];
    int h[maxn],tot=0,ans,f[maxn],all;
    void add(int u,int v) {
    	if (ck[u]!=tim) ck[u]=tim,h[u]=0;
    	e[++tot]=(edge){v,h[u]};
    	h[u]=tot;
    }
    void dfs(int x) {
    	f[x]=0;
    	if (ck[x]!=tim) h[x]=0;
    	for (int i=h[x],v=e[i].v;i;i=e[i].nxt,v=e[i].v) dfs(v),f[x]^=f[v];
    	++f[x];
    }
    int main() {
    	#ifndef ONLINE_JUDGE
    	freopen("test.in","r",stdin);
    	#endif
    	int T=read();
    	while (T--) {
    		scanf("%s",s+1);
    		n=strlen(s+1);
    		top=ans=0;
    		for (int i=1;i<=n;++i) {
    			if (!top) {
    				++tim,tot=all=0;
    				sta[++top]=++all;
    				continue;
    			}
    			if (s[i]=='(') {
    				int u=sta[top];
    				sta[++top]=++all;
    				add(u,all);
    			} else --top;
    			if (!top) {
    				dfs(1);
    				ans^=f[1];
    			}
    		}
    		puts(ans?"peipei":"iamcs");
    	}
    	return 0;
    }
    
  • 相关阅读:
    Mac item 远程连接服务器
    搭建私人Git Server
    数据结构第三章小结
    第二章实践小结
    poj3617 Best Cow Line
    最长上升子序列问题
    Uva11450 Wedding shopping
    poj3050 hopscotch
    poj2718 Smallest Difference
    poj3669 Meteor Shower
  • 原文地址:https://www.cnblogs.com/owenyu/p/6724634.html
Copyright © 2011-2022 走看看