zoukankan      html  css  js  c++  java
  • 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 }
    博弈论
  • 相关阅读:
    为什么要用getBaseContext()方法代替this?(转)
    如何让EditText不能自动获取焦点(转)
    context和getApplicationContext()的区别
    Idea 破解
    mysql 免安装
    AngularJS
    GC垃圾回收机制
    JVM类加载机制
    线程池
    面试-数据库
  • 原文地址:https://www.cnblogs.com/Alan-Luo/p/10193048.html
Copyright © 2011-2022 走看看