CodeForces 455B A Lot of Games

题目链接:http://codeforces.com/problemset/problem/455/B


题意:两个人玩游戏,给n个字符串,两个人轮流选一个字母加到字符串后面,一开始字符串是空的,而且加完后当前字符串必须是字符串集合中一个字符串的前缀,谁无法再添加字符串谁就输了,他们玩k局这个游戏,上一局输的人下一局先手,问第一局的先手必胜还是后手必胜。


思路:首先建一个trie树去保存这些字符串,剩下的就是一个博弈问题了。如果先手可以控制输赢,那么他可以前面几局一直输下去,最后一局再赢;先手怎么走都赢,那么下一局就是对手先手,下一局再回到自己先手...就可以通过判断奇偶来得到解决;先手必输,那么下一局还是自己先手,一直输下去,永无翻身之地....;先手不管怎么走,后手都可以控制输赢,更赢不了。


#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>
using namespace std;

#define rep(i,j,k) for (int i=j;i<=k;i++)
#define Rrep(i,j,k) for (int i=j;i>=k;i--)

#define Clean(x,y) memset(x,y,sizeof(x))
#define LL long long
#define ULL unsigned long long
#define inf 0x7fffffff
#define mod 100000007
const int maxn = 100009;
const int maxnode = 100009;
const int sz = 26;
LL n,k;

struct trie
{
	int next[maxnode][sz];
	int size; // 当前大小
	trie()
	{
		size = 0;
		memset(next,0,sizeof(next));
	}
	void insert(char s[])  //插入一个字符串
	{
		int len = strlen(s);
		int now = 0;
		for( int i = 0; i < len; i++ )
		{
			int index = s[i] - 'a'; //当前字符对应的下一个节点的下标
			if ( !next[now][index] )
			{
				next[now][index] = ++size;  //新开一个节点
			}
			now = next[now][index];
		}
	}
}T;

char temp[maxn];

int can( int now , int len ) // 0 1 2 3  -> 2表示必胜  1 必输  3可以控制输赢  0被控制输赢
{
    int temp;
    bool f1,f2,f0;
    f1 = f2 = f0 = false;

    rep(i,0,25)
        if ( T.next[now][i] )
        {
            temp = can( T.next[now][i] , len+1 );
            if ( temp == 0 ) return 3; //对手被控制输赢
            else if ( temp ==  1 ) f2 = true;//对手必输
            else if ( temp == 2 ) f1 = true;
            else if ( temp == 3 ) f0 = true;
        }
    if ( f1 && f2 ) return 3; //又可以赢又可以输
    if ( f1 ) return 1;
    if ( f2 ) return 2;
    if ( f0 ) return 0; //只能被控制输赢
    return 1; //剩下的情况就只有必输了
}

int main()
{
    cin>>n>>k;
    getchar();
    rep(i,1,n)
    {
        gets(temp);
        T.insert(temp);
    }
    int ans = can( 0 , 1 ); // 2 win   1 lose
    if ( ans == 3 || ( ans == 2 && ( k & 1 ) )  )
        puts("First");
    else puts("Second");
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值