zoukankan      html  css  js  c++  java
  • CodeForces 456D&455B--A Lot of Games(Trie+博弈)

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

    题解:

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

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

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

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

    --

    或者说如果所有的子节点都是必输,那么该节点必赢,如果所有的子节点都是必赢,那么该节点必输,如果子结点既有必赢又有必输,该节点可输可赢,如果子结点全都是可输可赢,那么该结点不可控制。

    如果一个结点是叶子结点,必赢。

    如果开始的时候是可输可赢,那么只要一只赢就好了。

    如果开始的时候是必输,那么你就会一直先手,一直输。

    如果是必赢,那么两个人轮流赢,判断奇偶。

    如果是不可控制,对手会让你前n-1轮赢,最后一轮输。

    #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");
        }
    }
  • 相关阅读:
    Linux内存、Swap、Cache、Buffer详细解析
    深入浅出前端本地储存
    Javscript字符串常用方法总结
    Python优雅日志记录器-Loguru
    Flume推送数据到SparkStreaming案例实战和内幕源码解密
    SparkStreaming数据源Flume实际案例分享
    基于HDFS的SparkStreaming案例实战和内幕源码解密
    Scala和Java二种方式实战Spark Streaming开发
    StreamingContext、DStream、Receiver深度剖析
    案例动手实战并在电光石火间理解其工作原理
  • 原文地址:https://www.cnblogs.com/wenruo/p/5813879.html
Copyright © 2011-2022 走看看