来自信息学奥赛一本通T1819
题目描述:
游戏分为
k
k
k 轮,参与者共有2个。
给定一个由小写英文字母组成的字符串的集合
S
S
S,在每轮游戏开始时,会有一个空串,然后两人轮流在该串的末尾添加字符,并且需要保证新的字符串是
S
S
S 中某个串的前缀,直到有一方不能操作,则不能操作的一方输掉这一轮。
新的一轮由上一轮输的人先手,最后一轮赢的人获得游戏胜利。
假定双方都采取最优策略,求第一轮先手的一方能否获胜。
本以为自己逃脱了字符串的魔咒,结果你在博弈论最后一题来了个tire树???
那既然是tire树那么就交给要讲tire树的dalao来做吧。(雾)
啊,这道题非常的容易想到构造,直接建出一棵tire树,在树上跑一遍dfs看先手是否有必胜或必败策略再判断一下就可以了,如果当前点
x
x
x 的任意一个某个子节点
y
y
y 没有必胜策略,那么
x
x
x 就有必胜策略,同理必败策略也是如此,那就可以用一个有两个位的二进制数来表示,前一位表示是否有必胜策略,后一位表示是否有比败策略,转移的时候就是当前的答案或上所有儿子节点的答案取反(这里应改用异或3),还有一点就是显然叶子结点(没有出边的点)只有先手必败状态,那么就可以开始转移了。
再考虑一下不同策略的影响:
(1)先手既没必胜策略也没必败策略:那么这种状况是接下来不管走到哪对方都可以控制必胜或必败,接下来跳转到(4)一起证明;
(2)先手只有必败策略:非常显然,后手可以一直让先手输,使得先手下一句还是先手,一直输到底;
(3)先手只有必胜策略:那么显然这就和进行的局数有关了,如果为奇数则先手胜,偶数则后生胜;
(4)先手既有必胜策略又有必败策略:那么先手可以在前
k
−
1
k-1
k−1 轮保证自己输,使得自己可以在第
2
2
2 到
k
k
k 次保证自己的先手地位,再在第
k
k
k 次下出必胜策略赢得比赛。
时间复杂度
O
(
n
)
O(n)
O(n)。
在临近结尾在吐个槽,数据范围貌似没说清楚应为所有字符串长度加起来小于1e5,否则输入就直接超时了。然后这个代码我调了一个下午,因为小数据一直超时,搞得我整个人都不耐烦了。后来还看了书上的题解,发现思路没有问题,再理解了下它丑的要死 的代码,发现根本和我一样没有一点优化,那为什么会超时呢。。。再想了30分钟左右的光景,我随手加了一个O2它就过了。。。我非常的无语,为啥这oj还能自己开O2开关(平常用习惯了不能开O2的oj的某只蒟蒻如是说到)???这个故事告诉我们,如果无法优化时间的代码不妨手动开个O2试试(除非已知这oj无法开O2,比如HLOJ)?
code:
#include <bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
const int N=1e5+10;
int n,k,t,num,sum;
char s[N];
struct lol {
int trs[26];
int cln(){
for(int i=-1;++i<26;trs[i]=0);
}
} e[N*26];
int init(){
if(scanf("%d%d",&n,&k)==EOF) return 0;
return 1;
}
void inst(){//将新的字符串插入trie树
for(int i=-1,ans=1,now;++i<strlen(s);){
now=s[i]-'a';
e[ans].trs[now]?:e[e[ans].trs[now]=++num].cln();
ans=e[ans].trs[now];
}
}
int dfs(int x){//判断从当前节点x开始添加字符,是否有先手必胜或必败的策略
int cnt=0,fl=1;//fl表示是否有出边
for(int i=-1,y;++i<26;y=e[x].trs[i],!y?:(cnt|=dfs(y)^3,fl=0));
//如果有边则搜索下去,因为这时先后手换了,那么就要把答案反过来(异或3)
return fl?1:cnt;//如果这个点没有出边了,那么显然是先手必败的状态了
}
void work(){
e[num=1].cln();
for(int i=0;++i<=n;scanf("%s",s),inst());
sum=dfs(1);
//sum二进制有两位,前一位表示是否有必胜策略,后一位表示是否有必败策略
}
void prin(){
sum/2?
sum%2?
printf("HY wins!\n"):
printf(k&1?"HY wins!\n":"Teacher wins!\n"):
printf("Teacher wins!\n");
}
int main(){
for(;init();work(),prin());
return 0;
}
博弈论5道over,写拍拍他去了。