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

题意:给n个字符串。进行k次游戏。每局开始,字符串为空串,然后两人轮流在末尾追加字符,保证新的字符串为集合中某字符串的前缀,不能操作者输,新一轮由上一句输的人先手。

题解:

#看到此题毫无头绪,队友写了神(xiang)一样的sg函数,我在旁边默默说,不太对吧,应该求必输必赢什么的,然后……然后怎样?我也不知道了……

#应该好好想想的,不应该轻易放弃啊……

对于每个节点分成四种情况,必输,必赢,可输可赢,不可控制情况(即后手可输可赢)

当一个结点的子节点有一个必输的时候,该节点可以胜,当有一个子结点必赢,该节点可以败,当所有子节点都可输可赢,该节点不可控制。

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int KIND = 26;
const int MAXN = 100005;
int cnt_node;

struct node{
    int cnt;
    node* nt[KIND];
    void init(){
        cnt = 0;
        memset(nt, 0, sizeof(nt));
    }
} Heap[MAXN];

inline node* new_node()
{
    Heap[cnt_node].init();
    return &Heap[cnt_node++];
}

void insert(node* root, char *str)
{
    for(char *p = str; *p; ++p){
        int ch = *p - ‘a‘;
        if(root->nt[ch] == NULL)
            root->nt[ch] = new_node();
        root = root->nt[ch];
        ++root->cnt;
    }
}

void solve(node* root, int &x, int &y) {
    bool fg = true;
    x = y = 0;
    int u, v;
    for (int i = 0; i < 26; ++i) {
        if (root->nt[i]) {
            fg = false;
            solve(root->nt[i], u, v);
            if (!u) x = 1;
            if (!v) y = 1;
        }
    }
    if (fg) x = 0, y = 1;
}

char word[MAXN];
int main()
{
    int n, k;
    while(scanf("%d%d", &n, &k) != EOF)
    {
        cnt_node = 0;
        node *root = new_node();
        for(int i = 0; i < n; i++)
        {
            scanf("%s", word);
            insert(root, word);
        }
        int x, y;
        solve(root, x, y);
        if (x && y) puts("First");
        else if (k&1 && x) puts("First");
        else puts("Second");
    }
}
时间: 2025-01-02 00:18:07

CodeForces 456D&455B--A Lot of Games(Trie+博弈)的相关文章

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 455B A Lot of Games(博弈,字典树)

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

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局游戏 对于每局游戏,2个玩家轮流给一个空串加入一个小写字母使得加完后的字符串不是n个字符串的前缀. 输家下一轮先手 问是先手必胜还是后手必胜 思路: 对于第一局游戏,若先手能到达必败态和必胜态,则先手会一直输到倒数第二局然后最后一局必胜 所以此时是first 若先手是必胜态或者是必败态,则是轮流赢.跟k的奇偶有关 #include <cstdio> #include <cstring> #include<iostream&g

Educational Codeforces Round 23 E. Choosing The Commander (trie)

题目链接: Educational Codeforces Round 23 E. Choosing The Commander 题意: 一共有n个操作. 1.  插入一个数p 2.  删除一个数p 3.  询问有多少个数 使得 x^p<l 题解: 对于前两种操作用01trie就能解决. 对于对三个操作,我们考虑在trie上搜索. 1.  当l的bit位是1时,那边bit位是p的字数全部的数都会小于l,(因为p^p=0) 2.  当l的bit为是0时,那边只能向bit位是p的子树中搜. 这样算下来

codeforces水题100道 第十六题 Codeforces Round #164 (Div. 2) A. Games (brute force)

题目链接:http://www.codeforces.com/problemset/problem/268/A题意:足球比赛中如果主场球队的主场球衣和客队的客队球衣颜色一样,那么要求主队穿上他们的可对球衣,现在有n个球队,每一球队的主场球衣和客场球衣的颜色都告诉你了,它们两两之间要比一场赛.求其中主队穿客场球衣的比赛场数.C++代码: #include <iostream> using namespace std; const int maxn = 33; int x[maxn], y[max

Codeforces 633C Spy Syndrome 2(DP+Trie树)

题目大概说给一个加密的字符串,加密规则是把原文转化成小写字母,然后各个单词反转,最后去掉空格.现在给几个已知的单词,还原加密的字符串. 和UVa1401一个道理.. 用dp[i]表示加密字符前i个字符都被解密时,最后所用单词编号,为0表示不能被解密 然后转移一个样,从i出发往前在Trie树上跑,看看能否找到不为0的dp[j],而str[j+1]str[j+2]...str[i-1]str[i]是单词 最后输出方案就根据dp里面的值从最后面回溯找到并输出即可 时间复杂度O(加密字符串长*单词最大长

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

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

codeforces 456d (字典树+DP)

题目大意:给定n,表示字符串集合.给定k,表示进行了k次游戏,然后是n个字符串.每局开始,字符串为空串,然后两人轮流在末尾追加字符,保证新的字符串为集合中某字符串的前缀,不能操作者输,新一轮由上一句输的人先手. 思路:00 代表不能控制 01代表败,10代表胜,11代表能输能赢 转自  http://blog.csdn.net/blankcqk/article/details/38459033 附带字典树模版: void insert(){ int len = strlen(s); int no