题目链接:Click
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
Months ago, the COVID-19 swept Wuhan. In order to control the outbreak, many people tried their best to help Wuhan, and with their help, we finally (almost) beat the virus, so we are going to set up a monument and write the names of all the contributors to express our gratitude to them. But there are so many people who have helped Wuhan so there are so many names to write, and how to arrange them is a big problem, so we decided that we will choose some representative names and rearrange their order to make them neatly. But until now we still do not know the maximum length of letters that will be write on the monument. We cannot leave enough space for these names without this number, so we leave this problem for you.
Now you will be given the name of all the contributors, and you can choose some and connect them in a certain order to make them neat. A permutation of names is neat only when for every component except the last one, the last letter of the component is the same as the first letter of the next component, and the last letter of the whole name is the same as the first one. E.g. if there are 3 contributors called ”abc”, “fga”, “cdef”, we can choose all these three names and combine them to “abccdeffga” to write on the monument with length of 10.
What’s more, these contributors agreed that one who contributed more is more important. They will provide you a preference list according to their agreement and you should connect the permutation strictly according to the list. That is, if a name s appears earlier than name t in the preference list, s would also appear earlier than tt if they are both selected into the permutations.
There will be many permutations which are neat, but we should leave enough space for every possible one, so can you tell us the length of the longest one?
Note: there might be multiple contributors have the same name.
The first line contains integer n,(1 ≤ n ≤ 2*105) - the number of contributors. Next n lines contain n names, one per line. A contributor’s name is a non-empty sequence of lowercase Latin letters. Its length does not exceed 10 characters.
Meanwhile, this is a preference list, the name comes earlier should also appear earlier in your final permutation.
Print a single number – the maximum length of combination of names. If there are no possible permutations, print 0 instead.
3
abc
ca
cba
6
For the first example, the final perutation will be “abccba”.
Please note that “cbaabc” is against the rule that “abc” should be important than “cba”.
4
aab
aab
lbwnb
mlslj
0
不看样例我还以为走错考场了呢,你确定这不是英语六级阅读理解?(还好我有Google翻译 )
大致意思是:
给你 n 个字符串,从中找一个最长子序列,要求该序列每一个字符串的最后一个字符和后一个字符串的第一个字符相等,并且,整个序列的第一个字符和最后一个字符相等
序列的长度为其中所有字符串的长度之和
看n的大小,2e5,基本上死了暴力那条心(暴力大致要O(n2))
(虽然我还是作死来了一发,果然TLE )
那对于这种求子序列的题目,其实应该有点感觉,是dp,但dp的主要问题是,如何寻找状态转移方程,如何确定每个维度的含义。
如果直接让dp数组表示合法状态(即,符合题目要求的序列),那么将无法完成转移,因为合法状态可能要从非法状态转移而来(序列首尾字符不相等),所以我们将退让一步,让dp保留"最长"这个属性,而在dp结束后筛查"合法状态",以保证状态的顺利转移。
如此定义:dp[i][j] 代表首字符为 i ,尾字符为 j 的子序列的最大长度。
此时放宽了要求(首位字符不一定相等)
状态转移方程:
dp[i][j]=max( dp[i][j],dp[i][x]+len )
假设目前单词首字符为 x, 尾字符为 j,长度为 len
用rmap记录目前的首字符r,是否在尾部出现过,以保证能连接
用集合s记录以r字符结尾的子序列的首字符
OK,上代码
"Talk is Cheap. Show me the Code."
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 2e5 + 5;
const int N = 128;
typedef long long ll;
char str[15];
bool rmap[N];
set<char>s[N];
int dp[N][N];
int main(void)
{
int n;
scanf("%d", &n);
while (n--) {
scanf("%s", str);
int len = strlen(str);
char l = str[0], r = str[len - 1];
rmap[r] = true;
s[r].insert(l);
dp[l][r] = max(dp[l][r], len);//初值
if (!rmap[l])continue;
for (set<char>::iterator iter = s[l].begin(); iter != s[l].end(); iter++) {
s[r].insert(*iter);//更新子序列首位字符对应
dp[*iter][r] = max(dp[*iter][r], dp[*iter][l] + len);
}
}
int ans = 0;
for (int i = 0; i < N; i++)//筛查合法状态
ans = max(ans, dp[i][i]);
printf("%d\n", ans);
return 0;
}
特别鸣谢:吴老板提供的技术支持