codeforces 455B A Lot of Games

题目

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");
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值