题解:AT_abc209_e [ABC209E] Shiritori

解题思路

考虑利用拓扑序逆推答案。

对于每一个单词,显然,只用考虑它的前 \(3\) 个字母和后 \(3\) 个字母。可以对每一种组合都编一个编号。

设当前字母组合为 \(s\),那么编号为 \(mp_s\)

建立一张图,从每个单词的后 \(3\) 个字母组成的字符串向前 \(3\) 个字母组成的字符串连一条边,并将节点 \(mp_{front}\) 的入度增加 \(1\)

然后根据拓扑序计算答案。

定义一个队列 \(q\),如果当前节点的入度为 \(0\),就把当前节点放到队列里面,并把状态设为必胜态。

对与每一个节点,如果它的前一个节点是必胜态,那么它就是必败态,反之亦然。

最后输出答案即可。

核心代码

建图:

rep(i, 1, n) {
	cin >> s[i];
	string t = "", tt = "";
	t += s[i][0], t += s[i][1], t += s[i][2];
	if (!mp[t]) mp[t] = ++ cnt;
	tt += s[i][s[i].size() - 3], tt += s[i][s[i].size() - 2], tt += s[i][s[i].size() - 1];
	if (!mp[tt]) mp[tt] = ++ cnt;
	g[mp[tt]].push_back(mp[t]);
	d[mp[t]] ++ ;
}

计算答案:

// 1 表示 Takahashi 必胜,-1 表示 Aoki 必胜,0 表示平局
queue<int> q;
rep(i, 1, cnt) if (!d[i]) {
	q.push(i);
	f[i] = 1;
}
while (!q.empty()) {
	int u = q.front();
	q.pop();
	rep(i, 0, g[u].size() - 1) {
		int ver = g[u][i];
		d[ver] -- ;
		if (f[ver] == 0 && f[u] == 1) {
			f[ver] = -1;
			q.push(ver);
		}
		if (f[ver] == 0 && f[u] == -1 && !d[ver]) {
			f[ver] = 1;
			q.push(ver);
		}
	}
}
posted @ 2024-10-25 14:42  zla_2012  阅读(2)  评论(0编辑  收藏  举报