codeforces 455B A Lot of Games

来源:互联网 发布:mac口红最火的颜色型号 编辑:程序博客网 时间:2024/06/05 16:09

题目

Andrew, Fedor and Alex are inventive guys. Now they invent the game with strings for two players.

Given a group of n non-empty strings. During the game two players build the word together, initially the word is empty. The players move in turns. On his step player must add a single letter in the end of the word, the resulting word must be prefix of at least one string from the group. A player loses if he cannot move.

Andrew and Alex decided to play this game k times. The player who is the loser of the i-th game makes the first move in the (i + 1)-th game. Guys decided that the winner of all games is the player who wins the last (k-th) game. Andrew and Alex already started the game. Fedor wants to know who wins the game if both players will play optimally. Help him.

中文题目

给定一组n个非空字符串。在游戏中,两个玩家一起构建单词,最初这个词是空的。玩家轮流操作。一个玩家操作时,必须在单词的末尾添加一个字母,结果形成的单词必须是至少一个字符串的前缀。一个玩家如果不能操作就会输掉这一轮。一局共有k轮,第k轮的胜者为最终的胜者。每一轮(非第k轮)的胜者为下一轮的后手。请问第一轮的先手还是后手有必胜策略。
当然,双方都很聪明。

题解

分为两部分

第一部分

是对字符串建trie树,然后如果无路可走则为P状态,如果只能转到N状态为P状态,否则为N状态
这样我们就可以求出每一轮的先手有没有必胜策略
顺便求出每一轮的先手有没有必败策略
(上面那句话是神来之笔???)

第二部分

如果先手既有必胜又有必败策略

他可以前k-1轮一直让自己输,最后一轮胜,最终胜

如果先手只有必胜策略

我们来归纳一下

k=1

显然先手胜

k=2

由于k=1时先手必胜,那么k=2时大家想让自己输,然而先手不存在必输策略,所以后手必胜

k=3

由于k=2时先手必输,那么k=3时大家想让自己赢,由于先手存在必赢策略,所以先手必胜

k=2*a+1

由于k=2*a时先手必输,那么k=2*a+1时大家想让自己赢,由于先手存在必赢策略,所以先手必胜

k=2*a

由于k=2*a-1时先手必胜,那么k=2*a时大家想让自己输,然而先手不存在必输策略,所以后手必胜

如果先手只有必输策略

你是不是认为是只有必赢反过来?
当然
不是啊
由于先手没有必胜策略,后手可以让他一直输,输k轮
所以后手必赢

如果先手都没有

这个就显然是命运都在后手手中
输输输
后手必赢

综上

如果先手既有必胜又有必败策略,必赢
如果先手只有必胜策略,如果k为奇数,先手必赢,反之后手必赢
如果先手没有必胜策略,后手必赢

代码

#include<cstdio>#include<cstring>#include<algorithm>#include<vector>#include<queue>using namespace std;const int N=100010,M=26,L=100010;struct node{    int ch[M];}tree[N];char s[L];int len;int ncnt;void add_trie(int& rt,int v){    if(!rt){        ncnt++;        rt=ncnt;    }    if(v==len)        return ;    add_trie(tree[rt].ch[s[v]-'a'],v+1);}bool is_win(int rt){    for(int i=0;i<26;i++)        if(tree[rt].ch[i])            if(!is_win(tree[rt].ch[i]))                return true;    return false;}bool is_lose(int rt){    bool flag=true;    for(int i=0;i<26;i++)        if(tree[rt].ch[i]){            flag=false;            if(!is_lose(tree[rt].ch[i]))                return true;        }    return flag;}int main(){    ncnt=1;    int n,m;    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++){        scanf("%s",s);        len=strlen(s);        int rt=1;        add_trie(rt,0);    }    bool win=is_win(1),lose=is_lose(1);    if(win)        if(lose)            printf("First");        else            if(m&1)                printf("First");            else                printf("Second");    else        printf("Second");}
原创粉丝点击