CF191A Dynasty Puzzles
首先感受一下 \(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\)。于是第一维就愉快地滚掉了。
转移的时候有几种情况:
- \(mx_{a,st_i}\neq 0\),意味着接在前面某个串后面,直接转移;
- \(mx_{a,st_i}=0\),也就是当前串是第一个。这有两种情况:
- \(a=st_i\),\(mx_{a,b}=ln_i\);
- \(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;
}
$\color{Red}\text{心怀荣耀,勇往直前。}$

浙公网安备 33010602011771号