[Trie树] Rima

文章目录

  • 题目
  • 题解
  • 代码


题目

题目描述

Adrian对单词押韵很感兴趣。如果两个单词的最长公共后缀的长度与两个单词中较长那个的长度一样,或者等于较长单词的长度减一,则这两个单词押韵。换句话说,如果A,B的最长公共后缀LCS(A,B)≥max(|A|,|B|)-1,则A和B押韵。

有一天,在阅读一套短篇小说时,他决定创造出能够使每两个相邻单词押韵的最长的单词序列,序列中的每个单词只能出现一次。但是Adrian已经厌倦了这个任务,所以他决定回去读小说,并要求你代替他解决这个任务。

输入

第一行输入包含整数N(1≤N≤5*1e5)。表示单词的个数。

接下来N行每行包含一个只由小写英文字母组成的字符串。表示可以用于组成序列的单词。数据保证每个单词都是不同的,保证所有单词的长度之和不超过3*1e6。

输出

输出一个整数。表示单词序列的最长长度。

样例输入

4
honi
toni
oni
ovi

样例输出

3

题解

Trie树不用说了吧,应该一下就能看出来,就是要反向建树

然后就是一波神奇的操作,我们用树形DP搞,定义 d p [ i ] dp[i] dp[i]为从 i i i节点往下连续终结点(就是一个字符串结束的点)的最大值

然后我们就可以用这个 d p dp dp做答案了,定义 a n s [ i ] ans[i] ans[i] i i i点往下能得到的所有字符串组合所能得到的最大序列,那么 a n s [ i ] ans[i] ans[i]等于 d p [ s o n ( i ) ] dp[son(i)] dp[son(i)]中最大的两个加上 i i i的儿子数减二

为什么是最大的两个呢?因为题目说的序列中相邻的两个串要押韵,所以我们需要用最短的那个串来过渡,但这个串只能用一次,为了将它利用到最大,我们用来过渡最大的两个,剩下的就不可能全部选了,只能将兄弟节点选进来(建议画个图,再结合我写的理解)

代码

这题考试时卡空间,要用vector,但我考场试vector好像样例都会TLE,结果测下来MLE爆炸,这个代码没用vector

#include 
#include 
#include 
#include 
#include 

using namespace std;

const int M = 3000005;

pair <int, int> maxn[M];

int n, m = 1, ans;
int trie[M][30], sum[M], dp[M];
char s[M];
bool shutDown[M];

void insert(char *s) {
	int len = strlen(s + 1);
	int root = 1;
	for(int i = len; i >= 1; i --) {
		int p = s[i] - 'a';
		if(trie[root][p] == 0) trie[root][p] = ++ m;
		root = trie[root][p];
	}
	shutDown[root] = 1;
}

void dfs(int x) {
	for(int i = 0; i <= 25; i ++) {
		if(trie[x][i] == 0) continue;
		dfs(trie[x][i]);
		if(shutDown[trie[x][i]]) sum[x] ++;
		dp[x] = max(dp[x], dp[trie[x][i]]);
		if(dp[trie[x][i]] > maxn[x].first)
			maxn[x].second = maxn[x].first, maxn[x].first = dp[trie[x][i]];
		else if(dp[trie[x][i]] > maxn[x].second)
			maxn[x].second = dp[trie[x][i]];
	}
	if(shutDown[x]) dp[x] += max(1, sum[x]);
	else dp[x] = 0;
}

int main() {
	scanf("%d\n", &n);
	for(int i = 1; i <= n; i ++) {
		scanf("%s", s + 1);
		insert(s);
	}
	dfs(1);
	for(int i = 1; i <= m; i ++)
		ans = max(ans, maxn[i].first + maxn[i].second + shutDown[i] + max(0, sum[i] - 2));
	printf("%d\n", ans);
	return 0;
}

你可能感兴趣的:(Trie树)