UVALive 7832 Dictionary Game解题报告(字典树+树上删边游戏)

question

    We all know the famous game scrabble, where we want to make words using tiles. We will play a game with words. But it is reverse of scrabble. Here instead of making words we want to destroy them. It is a two player game.
    The game starts with a dictionary of words. At each move, the current player chooses a word of his choice (not necessarily from the dictionary). The constraints for choosing the word is, it must match the prefix of any (one or more) of the current dictionary words. When a player chooses a word as its move, all the dictionary words that has a prefix equal to the
chosen word, are split into two parts:
        1. The matched part without the last character of the chosen word.
        2. The unmatched part starting from the last character of the chosen word.
    We remove all the unmatched part from the dictionary and keep only the matched part in the dictionary. The words that don’t have matched prefix with the chosen word are kept intact in the dictionary. In this situation the next player makes its move in the same fashion. If the chosen word is of length 1, then all the dictionary words starting with that character will be removed.
    For example, if we have a dictionary consisting the following words:
               bangladesh
               bangalore
               band
               bandana
    Now if the first player chooses the word “bang” then after the move the dictionary will become:
                ban
                ban
                band
                bandana
    A player loses, when it cannot make a valid move. Given the dictionary of words, who will win if both players played optimally? To make it more interesting, can you find out who will win if you update the dictionary by adding new words?
    Formally, you will be given few operations where you need to add a new word to the dictionary. After adding you need to calculate the winner between player 1 and 2 for the current dictionary. These added words are permanent. Means each of these added words will remain in the dictionary for that particular test case.

Input
    First line consists of an integer T , which is the number of test cases (T ≤ 10).
    Each case will start with an integer N (0 < N ≤ 50000), the number of words in the dictionary. Next N lines will contain dictionary words DW. Length of each DW will be less than or equal to 40.
    Next line will contain an integer number Q, the number of operations (0 < Q ≤ 50000).

    Next Q lines will contain query words QW. Each QW is the word that you now want to add to the current dictionary. Let’s call these “Query words”. Length of each QW will be less than or equal to 40. All the dictionary words and query words will only consist of lower case letters.
Output
    For each query word QW, you have to find out who will win, if you add QW to the current dictionary. First print the case number, then for each query print ‘1’ or ‘2’ based on whether player 1 or 2 will win.
Sample Input
2
4
bangladesh
bangalore
band
bandana
2
egg
apple
1
orange
2
cat
tiger
Sample Output
Case 1:
2
1
Case 2:
1
2

 

直接根据输入建立字典树,然后树上删边求sg即可

 

 

#include <cstdio>
#include <queue>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <map>
#include <algorithm>
#include <vector>
#define OUT freopen("out.txt","w",stdout)
#define mem(a,b) memset(a,b,sizeof (a))
#define DEBUG(a) cout << (a) << endl
#define lowbit(a) ((a)&(-a))
#define IN freopen("in.txt","r",stdin)
#define IO ios::sync_with_stdio(false);\
        cin.tie(0);\
        cout.tie(0);
using namespace std;
typedef long long ll;
const int maxn = 5e6+10;
const int PI = acos(-1);
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
struct tire{
    int son[26];
    int f;
}a[maxn];
int sg[maxn];
int tot;
string s;

int _insert(){
    int root = 0;
    for(int i=0;i<s.size();i++){
        int buf = s[i] - 'a';
        if(!a[root].son[buf]){
            a[root].son[buf]  = ++tot;
            a[tot].f = root;
        }
        root = a[root].son[buf];
    }
    return root;
}

void cal(int x){
    sg[x] = 0;
    for(int i=0;i<26;i++)
        if(a[x].son[i])
            sg[x] ^= sg[a[x].son[i]] + 1;
}
void dfs(int x){
    for(int i=0;i<26;i++)
        if(a[x].son[i])
            dfs(a[x].son[i]);
    cal(x);
}

void update(int x){
    while(x){
        cal(x);
        x = a[x].f;
    }
    cal(0);
}

int main(){
   // IN;
    int t,n;
    cin >> t;
    int step = 0;
    while(t--){
        //DEBUG(t);
        //    DEBUG("");
        tot = 0;
        printf("Case %d:\n",++step);
        cin >>n;
        for(int i=0;i<n;i++){
            cin >> s;
            _insert();
        }
        dfs(0);
        cin >> n;
        for(int i=0;i<n;i++){
            cin >> s;
            update(_insert());
            DEBUG(sg[0]?"1":"2");
        }
        for(int i=0;i<=tot;i++){
            a[i].f = 0;
            mem(a[i].son,0);
        }
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值