[杂题]: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++