抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

题目传送门

题意

给定大小为 \(n\) 的字符集和 \(m\) 个单词,第 \(i\) 个单词以字符 \(a_i\) 开头,以字符 \(b_i\) 结尾。

Snuke 和 Sothe 轮流玩单词接龙游戏(Snuke 先手)。每次游戏那个人必须说出一个以上个单词的末尾字符开头的单词,第一个人必须说出一个以字符 1 开头的单词。若轮到该人进行游戏时,说不出符合条件的单词,则该人失败。

假设两人绝对聪明,判断谁是胜者或者游戏会永远进行下去。

\(n\le 10^5,m\le 2\times 10^5\)

题解

每个字符当作一个状态,建出游戏图(\(a_i\to b_i\))。若游戏图中某个点的所有儿子都是必胜态,则当前点必败;若当前点的所有儿子中有一个状态是必败,则当前点必胜;否则为平局。

直接用 dfs 会因为有环而变得很难搞(求助路过的 dalao 帮蒟蒻看一下 代码,WA 3个点 QAQ),所以考虑建反图,倒着推。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <cstdio>
#include <cctype>
#include <cstring>
int read(){
register int x = 0, ch = getchar();
for (; !isdigit(ch); ch = getchar()) ;
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ '0');
return x;
}
#define N 100005
#define M 200005
int n, m, f[N], h, t, Q[N], d[N];
int edge, to[M], pr[M], hd[N];
void addedge(int u, int v){ // 连边
to[++edge] = v, pr[edge] = hd[u], hd[u] = edge;
}
int main(){
n = read(), m = read();
for (register int i = 1, x, y; i <= m; ++i)
x = read(), y = read(), addedge(y, x), ++d[x]; // 倒推,反向连边
h = 0, t = 0;
for (register int i = 1; i <= n; ++i) if (!d[i]) Q[++t] = i, f[i] = 2; // 边界状态
while (h < t){
int u = Q[++h];
if (f[u] == 2) // 当前状态必败
for (register int i = hd[u]; i; i = pr[i])
!f[to[i]] ? Q[++t] = to[i] : 0, f[to[i]] = 1; // 则父状态必胜
else // 当前状态必胜
for (register int i = hd[u]; i; i = pr[i])
if (!(--d[to[i]])) Q[++t] = to[i], f[to[i]] = 2; // 所有后继状态都是必胜,则必败
}
if (f[1] == 0) printf("Draw\n");
else if (f[1] == 1) printf("Snuke\n");
else if (f[1] == 2) printf("Sothe\n");
}

评论