[杂题]:staGame(博弈论+Trie树+DFS)

题目描述

$pure$和$dirty$决定玩$T$局游戏。对于每一局游戏,有$n$个字符串,并且每一局游戏由$K$轮组成。具体规则如下:在每一轮游戏中,最开始有一个空串,两者轮流向串的末尾添加一个字符,并且需要保证该串为$n$个字符串中任意一个串的前缀,不能操作的人输掉这一轮,并且在下一轮游戏中由该轮输掉的人先手。另外为了遵循女士优先的原则,在每一局游戏的第一轮均由$pure$先手。
玩家的目标是获得整局游戏的胜利,一局游戏的胜利条件是:对手输掉最后一轮游戏。我们可以假定$pure$和$dirty$都足够聪明。
现在,对于每一局游戏,$pure$想知道获胜者是谁。


输入格式

第一行一个整数$T$,表示游戏局数。
接下来$T$组数据,每组数据第一行两个整数$n,K$,表示字符串数和轮数,接下来$n$行,每行一个字符串。


输出格式

对于每一局游戏,输出一行$"Pure"$或者$"Dirty"$表示获胜者。


样例

样例输入:

2
2 3
a
b
1 2
ab

样例输出:

Pure
Dirty


数据范围与提示

对于$10\%$的数据,字符串总长不超过$5$,且$K\leqslant 2$;
对于$20\%$的数据,字符串总长不超过$5$;
对于另外$20\%$的数据,$K=1$;
对于$100\%$的数据,$1\leqslant n\le 10^5;1\leqslant K\leqslant 10^9; 1\leqslant T\leqslant 10$,每局游戏字符串总长不超过$10^5$,其中字符串非空且均为小写英文字母。


题解

这也许是我写的第一篇有关博弈论的题解。

我们先将所有的串建在$Trie$树上,那么如果你选了某个叶子节点,那么你就赢了;否则你就输了。

也就是在$Trie$树上跑一个$DFS$即可求出答案。

听起来是不是很简单?

时间复杂度:$\Theta(\sum S)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
int n,K;
char ch[100001];
int trie[100001][30],cnt;
int ans[100001];
void pre_work()
{
	cnt=1;
	memset(trie,0,sizeof(trie));
	memset(ans,0,sizeof(ans));
}
void insert(char *str)
{
	int len=strlen(ch+1),p=1;
	for(int i=1;i<=len;i++)
	{
		int c=str[i]-'a'+1;
		if(!trie[p][c])trie[p][c]=++cnt;
		p=trie[p][c];
	}
}
void dfs(int x)
{
	bool flag=0;
	for(int i=1;i<=26;i++)
		if(trie[x][i])
		{
			dfs(trie[x][i]);
			flag=1;
			ans[x]|=(ans[trie[x][i]]^3);
		}
	if(!flag)ans[x]=1;
}
int main()
{
	int T;scanf("%d",&T);
	while(T--)
	{
		pre_work();
		scanf("%d%d",&n,&K);
		for(int i=1;i<=n;i++)
		{
			scanf("%s",ch+1);
			insert(ch);
		}
		dfs(1);
		if(ans[1]==3||(ans[1]==2&&(K&1)))puts("Pure");
        else puts("Dirty");
	}
	return 0;
}

rp++

posted @ 2019-09-28 18:15  HEOI-动动  阅读(192)  评论(0编辑  收藏  举报