Codeforces 455B A Lot of Games 字典树上博弈

题目链接:点击打开链接

题意:

给定n个字符串,k局游戏

对于每局游戏,2个玩家轮流给一个空串加入一个小写字母使得加完后的字符串不是n个字符串的前缀。

输家下一轮先手

问是先手必胜还是后手必胜

思路:

对于第一局游戏,若先手能到达必败态和必胜态,则先手会一直输到倒数第二局然后最后一局必胜

所以此时是first

若先手是必胜态或者是必败态,则是轮流赢。跟k的奇偶有关

#include <cstdio>
#include <cstring>
#include<iostream>
#include <queue>
#include <set>
#include <map>
#include <string>
using namespace std;
#define Word_Len 100500
#define Sigma_size 26
#define ll int
struct Trie{
	ll ch[Word_Len][Sigma_size];	 //Word_Len是字典树的节点数 若都是小写字母Sigma_size=26
	ll sz ;						 //当前节点数
	bool win[Word_Len], lost[Word_Len];
	ll Newnode(){memset(ch[sz], 0, sizeof(ch[sz])); return sz++;}
	void init()							 //初始化字典树
	{ sz = 0; Newnode();}//初始化
	ll idx(char c){return c-‘a‘;}	 //字符串编号

	void insert(char *s){	 //把v数字加给 s单词最后一个字母
		ll u = 0, len = strlen(s);
		for(ll i = 0; i < len; i++){
			ll c = idx(s[i]);
			if(!ch[u][c])		     //节点不存在就新建后附加
				ch[u][c] = Newnode();
			u = ch[u][c];
		}			//如今的u就是这个单词的最后一个位置
	}
    void dfs(int u){
        int cnt = 0;
        for(int i = 0; i < 26; i++)if(ch[u][i])
        {
            cnt++;
            int v = ch[u][i];
            dfs(v);
            if(win[v]==false)win[u] = true;
            if(lost[v]==false)lost[u] = true;
        }
        if(cnt==0)
            lost[u] = true;
    }
};
Trie ac;
int n, k;
void input(){
    ac.init();
    char s[100005];
    while(n--)
    {
        scanf("%s", s);
        ac.insert(s);
    }
}
int main(){
	int i, j;
    while(~scanf("%d %d",&n,&k)){
		input();
        ac.dfs(0);
        if(ac.lost[0]==false && ac.win[0])
            puts(k&1 ?

"First":"Second");
        else if(ac.win[0] && ac.lost[0])
            puts("First");
        else puts("Second");
	}
	return 0;
}
时间: 2024-12-21 23:36:06

Codeforces 455B A Lot of Games 字典树上博弈的相关文章

Codeforces 455B A Lot of Games(字典树+博弈)

题目连接: Codeforces 455B A Lot of Games 题目大意:给定n,表示字符串集合.给定k,表示进行了k次游戏,然后是n个字符串.每局开始,字符串为空串,然后两人轮流在末尾追加字符,保证新的字符串为集合中某字符串的前缀,不能操作者输,新一轮由上一句输的人先手. 解题思路:首先对字符集合建立字典树,然后根据博弈的必胜必败性质搜索出先手的决策状态,可决定胜败3,只能胜利2,只能失败1,不可掌控(即对手可决定胜败)0. 对于状态3,为必胜,可以采用前K-1场败,然后保证第K场自

codeforces 455B A Lot of Games(博弈,字典树)

题目大意:给定n,表示字符串集合.给定k,表示进行了k次游戏,然后是n个字符串.每局开始,字符串为空串,然后两人轮流在末尾追加字符,保证新的字符串为集合中某字符串的前缀,不能操作者输,新一轮由上一句输的人先手. 解题思路:首先对字符集合建立字典树,然后根据博弈的必胜必败性质搜索出先手的决策状态,可决定胜败3,只能胜利2,只能失败1,不可掌控(即对手可决定胜败)0. 对于状态3,为必胜,可以采用前K-1场败,然后保证第K场自己先手,取必胜方案. 对于状态2,无论则们走都是赢的话,肯定是两个人轮流胜

codeforces 455B A Lot of Games (Trie + dfs)

题目大意: 两个人往一个空的字符串里填单词,每一次只能填一个,而且填完之后要是给出的N个字符串的前缀. 思路分析: 先用给出的所有单词建字典树. 然后从根节点开始dfs. win [x] 表示踩在x节点上是否有必胜策略 lose [x] 表示踩在x节点上是否有必败策略. 然后是博弈的过程. 如果先手有必胜和必败的策略,那么他可以一直输到k-1 如果只有必胜策略.那么只有当k为奇数的时候它才能赢. 其他为后手赢. #include <cstdio> #include <iostream&g

CodeForces 456D&amp;455B--A Lot of Games(Trie+博弈)

题意:给n个字符串.进行k次游戏.每局开始,字符串为空串,然后两人轮流在末尾追加字符,保证新的字符串为集合中某字符串的前缀,不能操作者输,新一轮由上一句输的人先手. 题解: #看到此题毫无头绪,队友写了神(xiang)一样的sg函数,我在旁边默默说,不太对吧,应该求必输必赢什么的,然后……然后怎样?我也不知道了…… #应该好好想想的,不应该轻易放弃啊…… 对于每个节点分成四种情况,必输,必赢,可输可赢,不可控制情况(即后手可输可赢) 当一个结点的子节点有一个必输的时候,该节点可以胜,当有一个子结

字典树+博弈 CF 455B A Lot of Games(接龙游戏)

题目链接 题意: A和B轮流在建造一个字,每次添加一个字符,要求是给定的n个串的某一个的前缀,不能添加字符的人输掉游戏,输掉的人先手下一轮的游戏.问A先手,经过k轮游戏,最后胜利的人是谁. 思路: 很显然先将n个字符串插入到字典树上,因为字典树上有分叉,不能仅仅判断字符串长度奇偶性来判断.字典树看成无环的状态图,如果按照拓扑排序逆序进行排序,在判断每个节点的时候,它的后继都已经判断过了.定义两个数组can_win[u], can_lose[u],表示u节点走下去“可能赢吗?”以及u节点走下去”可

codeforces 455B(博弈+dp)

题目链接: codeforces 455B 题目大意: 给出n个字符串,进行k次游戏,每次游戏输家下次作为先手,游戏规则为每次放一个字母,导致当前构造的字符串是给定的任意一个字符串的前缀,不能操作时为输,赢得第k次比赛的人会取得最终的胜利,问两人都采取最优策略的情况下,谁会赢得比赛. 题目分析: 首先针对这种字符串的问题我们很容易会想到利用字典树来解决,方便多模式匹配. 然后我们就能想到,这其实就是一个在树上的博弈,那么我们就可以通过dp知道先手是否有必胜策略和必败策略. 这个树上的博弈很基础,

51nod_1490: 多重游戏(树上博弈)

题目链接 该题实质上是一个树上博弈的问题.要定义四种状态--2先手必胜 1先手必败 3可输可赢 0不能控制 叶子结点为先手必胜态: 若某结点的所有儿子都是先手必败态,则该结点为先手必胜态: 若某结点的所有儿子都是先手必胜态,则该结点为先手必败态: 若某结点的儿子既有先手必胜态,又有先手必败态,或者是存在不能控制态,则该状态为可输可赢: 若某节点的所有儿子都是可输可赢态,则该结点为不能控制态. #include<bits/stdc++.h> using namespace std; typede

Codeforces 514C Watto and Mechanism(字典树)

题目链接  Watto and Mechanism 题意  给出n个串(相当于字典),然后给出m个询问. 每个询问以字符串的形式给出,你需要改变这个字符串中的任意一个字符 (必须改变且只能改变一个) 如果改变之后可以成为n个串中的一个字符串,则输出YES, 否则输出NO. 字母集合为{a, b, c} 考虑字典树. 首先把n个单词插入字典树中. 询问的时候用dfs,flag表示搜索到当前是否已经改变过一个字符. 如果已经改变过那只能按照当前剩下的字符串一条路查询下去. 否则可以按老字符或新字符进

Codeforces 633 C Spy Syndrome 2 字典树

题意:还是比较好理解 分析:把每个单词反转,建字典树,然后暴力匹配加密串 注:然后我就是特别不理解,上面那种能过,而且时间很短,但是我想反之亦然啊 我一开始写的是,把加密串进行反转,然后单词正着建字典树,然后就TLE了,反着写就能过 真是百思不得解,然后我猜测可能是单词数目比较少 #include <cstdio> #include <iostream> #include <cstring> #include <cstdlib> #include <v