题解:CF191A Dynasty Puzzles
CF191A 题解
题面
题意
给定 \(n\) 个字符串,将其中一些字符串取出来并拼接在一起,满足拼接的前面一个字符串的结尾与拼接的后面一个字符串的开头相同,且拼接成的字符串的收尾相同。
例子:\(\text{asc cdlaks sloa}\)。
(无特殊意义,随便举的例子。)
思路
一看到这题就想到了 DP。
于是,设了一个二维数组 \(f\),\(f_{l,r}\) 表示字母 \(l\) 到字母 \(r\) 的最大长度。(就是以字符 \(l\) 开头,字符 \(r\) 结尾的字符串的最大长度)其中,字母均用数字表示。
所以对于一个字符数组 \(s\),\(len\) 为它的长度,有:
\(f[s[1]][s[len-1]]=len\)。
接下来要考虑转移的式子:
对于一个字符串(从 \(1\) 开始输入),设 \(l=s[1]-97+1,r=s[len]-97+1\)(因为 \(a\) 的 ASCLL 码为 \(97\)),枚举所有可能的开头 \(i(i\in[1,26])\),有两种情况:
- 不将这个字符串接入:则 \(f[i][r]=f[i][r]\);
- 将这个字符串接入:则 \(f[i][r]=f[i][l]+len\)。
两者取最大值即可,所以有:
\(f[i][r]=\max(f[i][r],f[i][l]+len)\)。
枚举完以后,咱们还要在权衡利弊一下,如果 \(f[l][r]<len\),那还不如直接就只要这个字符串,所以枚举完后还要有:
\(f[l][r]=\max(f[l][r],len)\)。
于是,这题就可以 AC 啦。
总结
- 用数字表示字母。
- 线性 DP。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
long long n,f[35][35],ans,len,l,r;
//f[l][r] 表示字母 l 到字母 r 的最大长度
char s[15];
int main(){
scanf("%lld",&n);
for(int i=1; i<=n; i++){
scanf("%s",s+1);
len=strlen(s+1);
l=s[1]-'a'+1,r=s[len]-'a'+1;
for(int j=1; j<=26; j++)
if(f[j][l])
f[j][r]=max(f[j][r],f[j][l]+len);
f[l][r]=max(f[l][r],len);
}
for(int i=1; i<=26; i++) ans=max(ans,f[i][i]);
printf("%lld\n",ans);
return 0;
}