20181228 模拟赛 T3 字符串游戏 strGame 博弈论 字符串

3  字符串游戏(strGame.c/cpp/pas)

3.1  题目描述

pure 和 dirty 决定玩 T 局游戏。对于每一局游戏,有n个字符串,并且每一局游戏由K轮组成。具体规则如下:在每一轮游戏中,最开始有一个空串,两者轮流向串的末尾添加一个字符,并且需要保证该串为n个字符串中任意一个串的前缀,不能操作的人输掉这一轮,并且在下一轮游戏中由该轮输掉的人先手。另外为了遵循女士优先的原则,在每一局游戏的第一轮均由 pure 先手。

玩家的目标是获得整局游戏的胜利,一局游戏的胜利条件是:对手输掉最后一轮游戏。我们可以假定pure和dirty都足够聪明。

现在,对于每一局游戏,pure 想知道获胜者是谁。

 

3.2  输入格式

第一行一个整数 T,表示游戏局数。

接下来 T 组数据,每组数据第一行两个整数 n, K,表示字符串数和轮数,接下来n行,每行一个字符串。

 

3.3  输出格式

对于每一局游戏,输出一行``Pure''或者``Dirty''表示获胜者。

 

3.4  样例输入

2

2 3

a

b

1 2

ab

 

3.5  样例输出

Pure

Dirty

3 .6  数据范围与约定

对于 10% 的数据,字符串总长不超过5,且 K <= 2 ;

对于 20% 的数据,字符串总长不超过5;

对于另外 20% 的数据,K = 1;

对于 100% 的数据,1 <= n <= 105; 1 <= K <= 109; 1 <= T <= 10,每局游戏字符串总长不超过 10^5,其中字符串非空且均为小写英文字母。

 

分析:

  原来一直以为博弈论是玄学中的玄学,今天初见,原来也是一门非常美妙严谨的,玄学中的科学呢。

  我并不想谈SG函数,也就是说,假如你博弈论基础为0的话呢,也是可以看懂这篇报告的。

  仔细审题后我们会发现,我们要处理这些串的问题,又不能随便枚举,所以很容易想到建一棵trie树!(上来就想建各种自动机的dalao我只能跪%了)

  插一句话,据说在博弈论题目中呢,有一个套路就是把每次的局面当成节点,于是乎整个游戏的所有局面构成了一棵树(有的时候是DAG),随着游戏局面的推进,相当于在这张有向图上越走越深,这道题中显然只是一棵树,因为我们不可能不断加字母,完了还回到了一个之前状态的局面,那长度也不对劲啊!

  我们惊奇的发现,这棵所谓的局面树,和trie树差不多……哎!好像是一回事啊,不管是谁加字母,只会在这个树上越走越深,无字母可加时,这一方就失败了!

  所以我们可以了解,当一个点无路可走的时候,那这个点就是必败的状态。

  进而,我们可以利用回溯的过程,倒着求出每个点的状态,当一个点仅指向一个必败的点时,这个点就是必胜的,当这个点仅仅指向必胜的点时,这个点就是必败的(因为要交替进行嘛),当一个点既指向必胜又指向必败点时,这个点是既有胜的能力,又有败的能力的,当一个点仅仅指向一个胜败皆可的点时,它是既没有胜的能力也没有败的能力的(胜负完全掌握在对方手上)。

  所以,处于一个点时,所具备的对局势主导的能力只由这个点的所有子节点决定。

  并且,当前点的能力,就是它所有子节点的能力反过来的并集(即位运算的或)。

  所以我们用两位二进制来表示具备的输赢的能力,0表示都不具备,1表示只具备输的能力,2表示只具备赢的能力,3表示掌握大局(既能赢也能输),所以我们就可以想出递推式子:f[a]  |=  (f[ch[a][i]] ^ 3);(ch[a][i]是一个存在的子节点)

  这样呢,我们递推结束之后,只需要判断开始的节点(先手或后手)有怎样的能力,以及能否获得(先手或后手)的机会,来判断是否能取得最终的胜利。

  (获得先手机会的手段当然是一直输,最后一把你就是先手了)

代码:

 1 #include<bits/stdc++.h>
 2 #define ms(a,x) memset(a,x,sizeof(a))
 3 using namespace std;
 4 const int N=100005;
 5 int n,k,ch[N][26],p,f[N];char s[N];
 6 void ins(){
 7     int t=1,len=strlen(s+1);
 8     for(int i=1;i<=len;i++){
 9         int c=s[i]-'a';
10         if(!ch[t][c]) ch[t][c]=++p;
11         t=ch[t][c];
12     } return ;
13 } void dfs(int a){
14     bool flg=0;
15     for(int i=0;i<26;i++){
16         if(ch[a][i]){
17             dfs(ch[a][i]),flg=1;
18             f[a]|=(f[ch[a][i]]^3);
19         }
20     } if(!flg) f[a]=1;
21 } int main(){
22     freopen("strGame.in","r",stdin);
23     freopen("strGame.out","w",stdout);
24     int t;scanf("%d",&t);
25     while(t--){
26         scanf("%d%d",&n,&k);
27         ms(ch,0);ms(f,0);p=1;
28         for(int i=1;i<=n;i++)
29         scanf("%s",s+1),ins();
30         dfs(1);if(f[1]==3)puts("Pure");
31         else if(f[1]==2&&(k&1)) 
32         puts("Pure");
33         else puts("Dirty");
34     } return 0;
35 }
博弈论

 

posted @ 2018-12-28 21:45  杜宇一声  阅读(397)  评论(0编辑  收藏  举报