首页 > 其他分享 >ABC209E Shiritori 题解

ABC209E Shiritori 题解

时间:2023-10-20 11:22:54浏览次数:55  
标签:Shiritori large ABC209E 必败 题解 单词 必胜 int 平局

ABC209E Shiritori 题解

原题:洛谷AT_abc209_e

分析

博弈,可重复选,一眼图论,将每个单词的前三个字符向后三个字符连边,并用后三个字符代表这个单词。

看一下样例。

5
eaaaabaa
1    2
eaaaacaa
1    3
daaaaaaa
4    5
eaaaadaa
1    4
daaaafaa
4    6

我们得到的有向图:

当一方说完一个单词,这个单词的后三个字符无法接上任何单词的前三个字符则为必胜态。

即这个点没有出边,则这个点是必胜态。

注意,本题博弈的状态转移有些不同,具体为:

当一个点连向的点中有一个必胜态,则这个点是必败态

当一个点连向的点都是必败态,则这个点是必胜态

常见的状态转移:

当一个点连向的点中有一个必败态,则这个点是必胜态

当一个点连向的点都是必胜态,则这个点是必败态

分析一下,一方走到这个点之后,下一手是对方,也就是说对方决定了下一次要走哪条边。

那么对方肯定是想让当前点成为必败态,想要尽可能走到必胜态。所以就有了本题稍为不同的状态转移。

另两篇没有注意到这一点,文字叙述中说的是常见的状态转移或是笼统模糊地说了说,但代码实现却是对的,卡了我很长时间(

具体可以以 \(\large1\) 号点为例(虽然 \(\large1\) 号点在样例中并无实际意义,我们假定它也代表了一个单词):

首先 \(\large4\) 号点一定是必败态,因为 \(\large 5\) 和 \(\large 6\) 都是必胜态。

那么当一方说完 \(\large 1\) 号点代表的单词后,该对方接了,对方肯定会接 \(\large 2\) 或 \(\large 3\) 而不接 \(\large 4\)。因为只有走到这两点,才能使当前点败,他胜。

套路

我们观察到,所有有出边的点的状态都是由它连向的点(后继)转移而来的,所以我们使用有向图上博弈的常见套路——反向建边。然后跑拓扑同时状态转移就可以了。

到此,\(\operatorname{DAG}\) 上的本题就已经讨论完了,但是我们还没有判平局,即有环的情况。

平局(环)

有环是不一定平局的,分析一下。

(正向图中)在一个环里,一方说完了一个单词,如果对方可以走到必胜态,肯定会走处环使得自己胜而不是平局。但是如果这个环没有向外连边或连向的都是必败态,那么就是平局。

那么在反向图中,我们在遍历一个必胜的点的出边时,不必在后继的入度为零时才让它入队,直接把它的状态转移为必败并入队。若是遍历一个必败的点的出边,正常拓扑即可。

code

#include<bits/stdc++.h>
#define int long long
#define reg register
#define mp(a,b) make_pair((a),(b))
using namespace std;
inline int read()
{
	short f=1;
	char c=getchar();
	int x=0;
	while(c<'0'||c>'9')	{if(c=='-')	f=-1;c=getchar();}
	while(c>='0'&&c<='9')	x=(x<<1)+(x<<3)+(int)(c^48),c=getchar();
	return x*f;
}
int n,tot,ind[200010],win[200010]/*0平/未查找 1败 2胜*/;
string l,r[200010],s,ans[3]={"Draw","Aoki","Takahashi"};//不想写if了qwq
unordered_map<string,int>c;
vector<int>e[200010];
queue<int>q;
signed main()
{
	n=read();
	for(reg int i=1;i<=n;i=-~i)
	{
		cin>>s;l="";
		for(reg int j=0;j<3;j=-~j)	l+=s[j];
		for(reg int j=s.size()-3;j<(int)s.size();j=-~j)	r[i]+=s[j];
		if(!c[l])	c[l]=++tot;//没必要哈希,用map编号即可
		if(!c[r[i]])	c[r[i]]=++tot;
		e[c[r[i]]].push_back(c[l])/*反向建边*/;ind[c[l]]=-~ind[c[l]];
	}
	for(reg int i=1;i<=tot;i=-~i)	if(!ind[i])	q.push(i),win[i]=2;
	while(!q.empty())
	{
		int u=q.front();q.pop();
		for(reg auto i:e[u])
		{
			if(!win[i]&&win[u]==2)	q.push(i),win[i]=1;
			if(!win[i]&&win[u]==1&&!--ind[i])	q.push(i),win[i]=2;
		}
	}
	for(reg int i=1;i<=n;i=-~i)	cout<<ans[win[c[r[i]]]]<<endl;
	return 0;
}

标签:Shiritori,large,ABC209E,必败,题解,单词,必胜,int,平局
From: https://www.cnblogs.com/sorato/p/17776627.html

相关文章

  • Game Bundles 题解
    题目链接GameBundles分析很神奇的一道题目先想想如何计算一个集合和为60的子集个数可以想到通过\(DP\)求解:记\(f[i][j]\)为前\(i\)个数字,和为\(j\)的子集个数则\(f[i][j]+=f[i-1][j-a[i]]\)\(f[i][a[i]]++\)可以倒叙枚举\(j\)滚掉\(i\)这一维代码如下voi......
  • P9745 「KDOI-06-S」树上异或 题解
    原题挺好的树形dp,正好dp不太熟练,练习一下赛时只想到了暴力和\(X\leq7\)的链的部分分,过于naive不说了先考虑链的情况,既然是二进制考虑按位拆分。设\(g_{i,j,0/1}\)表示以\(i\)为根,从\(i\)点连通块的疑惑和第\(j\)位为\(0/1\),除去连通块部分的积的和。然后设......
  • P3119 [USACO15JAN] Grass Cownoisseur G 题解
    分析大概是强连通分量里面最水的一道紫题,不过细节挺多的,做题的时候给蒟蒻震惊到了。题目要求是从\(1\)走到某个点,然后再走回\(1\)号点,中途可逆行一次,问最多能经过几个点。有一个明显的思路是存两个图,一个正图一个反图,正图是为了求\(1\)到各个点的距离,反图是为了求各个点......
  • LuoguCF362B Petya and Staircases 题解
    分析简单排序题。首先Petya可以通过跨过一个台阶和两个台阶保证不经过脏台阶,但是不可以通过跨过三个台阶来保证不经过脏台阶,所以只要看有没有连续的三个脏台阶即可。同时,如果第一个台阶和最后一个台阶至少一个是脏台阶那么就不可以达成。AcceptedCode/*CodeByManipula*/......
  • CF424C的题解
    简单题。CF评分才*1600。可以直接先把\(Q\)拆成两部分。\[\begin{aligned}\largea&=\oplus^n_{i=1}p_i\\\largeb&=\oplus^n_{i=1}\oplus^n_{j=1}\\\(i\bmodj)\\\largeQ&=a\oplusb\end{aligned}\]\(a\)很好算,我们看一下\(b\)具体要怎么算。把\(b\)......
  • CF580B的题解
    见到有单调性、有限制的区间问题,很自然地就会想到用尺取去做。先按工资升序排序,然后套上尺取就行了。不会尺取的可以根据这道题去学。时间复杂度\(O(n\logn)\)。#include<cstdio>#include<algorithm>#definelllonglongusingnamespacestd;constintN=1e5+10;intn......
  • ARC166B题解
    发现还没有和我一样的做法。觉得B比A好想的多。令\(A_i\)为\(a_i\)变成\(A\)的倍数最少次数,\(B_i,C_i,AB_i,AC_i,BC_i,ABC_i\)同理。那么我们就有\(A_i=(A-A\bmod{a_i})\bmodA\),其他同理。这一大坨东西显然都能在\(O(n)\)的时间复杂度内算出来。剩下的就很好......
  • [题解]CF1881G Anya and the Mysterious String
    思路发现如果一个字符串中有长度大于等于\(2\)回文子串,必定有长度为\(2\)的回文子串或长度为\(3\)的回文子串,并且形如:aa和aba。所以考虑用线段树这两种情况。维护一段区间的最左、次左、最右、次右的元素,同时用两个标记变量\(f_1,f_2\)分别表示这个区间中是否出现形如......
  • [AGC020F] Arcs on a Circle 题解
    ArcsonaCircle首先,一个非常自然的想法是尝试断环成链。怎么断呢?我们发现,选择最长线段的起点处截断是个非常好的选择,因为不可能有一个线段完全覆盖它。这之后,一个紧接着的想法就是DP。假如把描述中的全部“实点”改成“整点”的话,那么这题是比较trivial的,可以通过随便状压......
  • 洛谷 P4749 [CERC2017] Kitchen Knobs 题解
    KitchenKnobs首先,一个trivial的想法是,因为每个旋钮如果上面的数字并非全部相同则其必有唯一最优位置,故直接扔掉那些全部相同的旋钮,对于剩余的求出其最优位置。明显此位置是一\(0\sim6\)的数。因为是区间同时旋转,所以转成数之后就是区间加同一个数。一个经典套路是差分。这......