先构造一个 trie
然后我有一个很暴力的想法
首先把字符串排序
然后按照顺序对每个字符串,我们把它首尾相接枚举起点
然后直接在 trie 里面暴力找?找得到就继承(类似 dp 转移那样)……
但是这样并不可行,复杂度太高了,承受不住
发现上面的过程可以看作是在图中转移
那么我们考虑对每个字符串,给它连边?
(枚举加上一个字符之后能够构成的所有字符串?)
这样的复杂度是
26
∗
2
L
e
n
+
1
n
26*2^{Len+1}n
26∗2Len+1n 那好像更沙雕了
我们考虑设计一种与字符所在位置无关的哈希
那么每次只需要随便多加一个就可以
26
n
26n
26n 预处理
然后我们在建出的 DAG 图里面随便搞一下
(因为这个 dag 的性质还有点特殊,所以你甚至可以直接 bfs )
(如果没有这个性质的话你可以拓扑排序也可以直接最长路)
(至于这个图边会有多少条。。。我就建议你开
26
n
26n
26n 吧
实际上边数上限可能是把
n
n
n 分成多个
26
26
26 和一个余数 然后相邻层连边?
反正我建议
26
n
26n
26n
并且可以注意到所谓与字符所在位置无关
实际上就是说,我们只关心每种字母出现了几次
那实际上就相当于把字符串里面每种字母出现了几次记一下 然后做普通的哈希
我觉得最好搞双哈希或者加一个冲突处理啥的
那我们发现这道题里面的字符串我们只关心每种字母的出现次数
然后对于每个字符串我们就可以:
往 trie 里面塞一条长度为 26 的链,从上到下代表 abcdefg…
上面每个点代表的就是这个字母的出现次数
同样可以搞掉这道题。
虽然空间好像有点卡,写起来也有一点点沙雕
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<stack>
#include<ctime>
#include<cstring>
#include<queue>
#include<cctype>
using namespace std;
int n = 1, tot;
string str[10005];
stack<int> stk;
int Siz[10005];
int Ap[10005][26];
int Markit[11451444];
const int MOD = 11451419;
int hzw[10005];
int head[10005], nxt[260005], to[260005];
int in[10005];
int Len[10005];
int Gkd[10005];
int Ans;
int AnsPos;
queue<int>Que;
#define add_edge(a,b) nxt[++tot] = head[a], head[a] = tot, to[tot] = b
int GetHash(const int& x)
{
int Ret = 0;
for (register int i = 0; i < 26; ++i)
{
Ret = (131ll*Ret) % MOD + Ap[x][i];
Ret %= MOD;
}
return Ret;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
while(cin >> str[n])
{
Siz[n] = str[n].size();
for (register int j = 0; j < Siz[n]; ++j)
{
++Ap[n][str[n][j]-'a'];
}
Markit[hzw[n] = GetHash(n)] = n;
++n;
}
--n;
for (register int itst, i = 1; i <= n; ++i)
{
for (register int j = 0; j < 26; ++j)
{
++Ap[i][j];
itst = GetHash(i);
if (Markit[itst])
{
add_edge(i, Markit[itst]);
++in[Markit[itst]];
}
--Ap[i][j];
}
}
for (register int i = 1; i <= n; ++i)
{
if (!in[i]) Que.push(i), Len[i] = 1;
}
while (!Que.empty())
{
int x = Que.front();
Que.pop();
for (register int i = head[x]; i; i = nxt[i])
{
--in[to[i]];
Len[to[i]] = Len[x] + 1;
Gkd[to[i]] = x;
if (!in[to[i]]) Que.push(to[i]);
}
}
for (register int i = 1; i <= n; ++i)
{
if (Len[i] > Ans) Ans = Len[AnsPos = i];
}
cout<<Ans<<endl;
while (AnsPos)
{
stk.push(AnsPos);
AnsPos = Gkd[AnsPos];
}
while (!stk.empty())
{
cout << str[stk.top()] << endl;
stk.pop();
}
return 0;
}