abcdeffa's Blog

当局者迷,旁观者清。

0%

GMOJ S5040 【押韵】

Description

给你 $n$ 个字符串 $S_1$ ~ $S_n$,定义两个字符串 $A$ 和 $B$ 押韵当且仅当:

现在要你从给出的这 $n$ 个字符串中选出一些,使得选出的任意相邻的两个字符串押韵,问你最多能够选出多少个字符串。

空间限制为 256MB。

Solution

考虑把字符串倒过来建 字典树

这样的话,对于字典树上是单词结尾的一个位置,他的答案就是以它为根的子树中的最长链 + 次长链(要和最长链没有公共边) + 其他儿子个数。

其中最长链和次长链的长度为这条链上是单词结尾的点的个数。

这种摆法也即先摆最长链,再摆根节点和根节点的其他儿子,最后再摆次长链。

最长链和次长链的维护和转移的具体实现见 Code 部分。

这个题的空间给的十分恶心,我迫不得已用了 unordered_map,各种卡常都过不去,最后只能够开各种编译优化来卡过去。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include <unordered_map>
#include <cstdio>
#include <cstring>
#define maxN 3000010
#define max(x, y) ((x) > (y) ? (x) : (y))
std::unordered_map<int, int> son[26];
struct edge{ int x, y, g; } b[maxN];
int Ans = 0, len = 0, tot = 0;
char st[maxN];
bool cu[26][maxN];
int f[maxN], g[maxN];
int sum[maxN], h[maxN], val[maxN];
void ins (int x, int y)
{
len++;
b[len].x = x;
b[len].y = y;
b[len].g = h[x];
h[x] = len;
}
void dfs (int x)
{
f[x] = g[x] = 1;
for(int i = h[x];i;i = b[i].g)
{
int y = b[i].y;
dfs(y);
if(val[y])
{
const int X = f[y] + sum[y] + val[y] - 1;
if(X >= f[x])
{
g[x] = f[x];
f[x] = X;
}
else if(X > g[x])
{
g[x] = X;
}
}
}
Ans = max(Ans, f[x] + g[x] + sum[x] + val[x] - 2);
}
int main ()
{
int n = 0;
scanf("%d", &n);
for(int i = 1;i <= n; i++)
{
int Len = 0;
char c = getchar();
while(c < 'a' || c > 'z')
{
c = getchar();
}
while(c >= 'a' && c <= 'z')
{
st[++Len] = c;
c = getchar();
}
int now = 0;
int fa = 0;
for(int j = Len;j >= 1; j--)
{
const int X = st[j] - 'a';
if(!cu[X][now])
{
cu[X][now] = true;
ins(now, son[X][now] = ++tot);
}
now = son[X][fa = now];
}
sum[fa]++;
val[now] = 1;
}
dfs(0);
printf("%d", Ans);
return 0;
}