CF191A Dynasty Puzzles

洛谷

codeforces

首先感受一下 \(2s\) 的时限还是很宽裕的,复杂度大概是 \(n\) 乘上一个什么东西。

于是 dp 状态肯定也不只有 \(n\)。大胆设 \(f_{i,a,b}\) 表示结尾是第 \(i\) 个串,并且首尾两个字符分别是 \(a\) 和 \(b\) 时的最长长度。

转移枚举 \(i\),再枚举 \(a\),注意到此时 \(b\) 一定为 \(s_i\) 的末位字符,不用枚举了。大体的转移方程:

\[f_{i,a,b}=\max f_{j,a,st_{i}}+ln_i \]

其中 \(st_i\) 是指 \(s_i\) 的第一个字符,\(ln_i\) 是串长。

显然时空都爆炸了,考虑优化:

转移的时候额外记录一个 \(mx_{a,b}\) 表示 \(\max\limits_{j<i} f_{j,a,b}\) 可以实现 \(\mathcal{O}(1)\) 转移。

但是这样空间还是爆炸的。其实 \(f\) 的第一维没有必要记录,每次转移时我们只关心 \(mx\) 里的值,而 \(mx\) 里的值一定来自 \(1\sim i-1\)。于是第一维就愉快地滚掉了。

转移的时候有几种情况:

  1. \(mx_{a,st_i}\neq 0\),意味着接在前面某个串后面,直接转移;
  2. \(mx_{a,st_i}=0\),也就是当前串是第一个。这有两种情况:
    1. \(a=st_i\),\(mx_{a,b}=ln_i\);
    2. \(a\neq st_i\),什么也不用做。

最后答案就是 \(\max\limits_{i=1}^n mx_{st_i,st_i}\)。时间复杂度 \(\mathcal{O}(26n)\)。

int n,m,k;
char s[N];
int st[N],ed[N],ln[N];
int f[30][30];
int mx[30][30];
int main()
{
	n=read();
	FOR(i,1,n){
		scanf("%s",s+1);
		ln[i]=strlen(s+1);
		st[i]=s[1]-'a'+1;ed[i]=s[ln[i]]-'a'+1;
	}
	FOR(i,1,n){
		FOR(a,1,26){
			int fst=st[i],lst=ed[i];
			if(mx[a][fst]>0)f[a][lst]=mx[a][fst]+ln[i];
			else f[a][lst]=mx[0][0];
			mx[a][lst]=max(mx[a][lst],f[a][lst]);
			if(a==fst&&mx[a][fst]==0)f[fst][lst]=mx[fst][lst]=max(mx[fst][lst],ln[i]);
		}
	}
	int ans=0;
	FOR(i,1,n) ans=max(mx[st[i]][st[i]],ans);
	printf("%d",ans);
	return 0;
}
posted @ 2024-06-12 20:46  LHLeisus  阅读(54)  评论(0)    收藏  举报