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; }
|