[NOI2015]品酒大会 - 后缀自动机
建出SAM和后缀树
两个子串的最长lcp就是他们的lca
因此我们只需求出最长的个数然后用前缀和就能算出总个数,最大值也是同样的方法, 当然要逆序建SAM才能保证他们的第一位相同。
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #define LL long long 6 7 using namespace std; 8 9 inline LL read() 10 { 11 LL x = 0, w = 1; char ch = 0; 12 while(ch < '0' || ch > '9') { 13 if(ch == '-') { 14 w = -1; 15 } 16 ch = getchar(); 17 } 18 while(ch >= '0' && ch <= '9') { 19 x = x * 10 + ch - '0'; 20 ch = getchar(); 21 } 22 return x * w; 23 } 24 25 const int MAXN = 1e6 + 10; 26 27 int head[MAXN]; 28 char s[MAXN]; 29 LL d[MAXN]; 30 LL ans[MAXN], num[MAXN]; 31 LL fi, se; 32 int flag[MAXN]; 33 LL size[MAXN]; 34 LL maxn[MAXN], minn[MAXN]; 35 int len; 36 int lst = 1, tot = 1; 37 38 struct SAM { 39 int c[27]; 40 int fa, len; 41 } t[MAXN]; 42 43 void extend(int x, int d) 44 { 45 int last = lst, np = ++tot; 46 t[np].len = t[last].len + 1; 47 size[np] = 1; 48 lst = np; 49 maxn[np] = minn[np] = d; 50 while(last && !t[last].c[x]) { 51 t[last].c[x] = np; 52 last = t[last].fa; 53 } 54 if(!last) { 55 t[np].fa = 1; 56 } else { 57 int q = t[last].c[x]; 58 if(t[q].len == t[last].len + 1) { 59 t[np].fa = q; 60 } else { 61 int nq = ++tot; 62 flag[nq] = 1; 63 maxn[nq] = -2e18, minn[nq] = 2e18; 64 t[nq] = t[q]; 65 t[nq].len = t[last].len + 1; 66 t[np].fa = t[q].fa = nq; 67 while(t[last].c[x] == q) { 68 t[last].c[x] = nq; 69 last = t[last].fa; 70 } 71 } 72 } 73 } 74 75 int cnt = 0; 76 77 struct edge { 78 int v, next; 79 } g[MAXN]; 80 81 void addedge(int u, int v) 82 { 83 g[++cnt].v = v; 84 g[cnt].next = head[u]; 85 head[u] = cnt; 86 } 87 88 bool ok(int x) 89 { 90 return maxn[x] != -2e18 && minn[x] != 2e18; 91 } 92 93 void DFS(int x) 94 { 95 for(int j = head[x]; j; j = g[j].next) { 96 int to = g[j].v; 97 DFS(to); 98 num[t[x].len] += size[x] * size[to]; 99 size[x] += size[to]; 100 if(ok(x) && ok(to)) { 101 ans[t[x].len] = max(ans[t[x].len], max(maxn[x] * maxn[to], minn[x] * minn[to])); 102 } 103 maxn[x] = max(maxn[x], maxn[to]); 104 minn[x] = min(minn[x], minn[to]); 105 } 106 } 107 108 int main() 109 { 110 //freopen("drink.out", "w", stdout); 111 len = read(); 112 scanf("%s", s + 1); 113 fi = -2e18, se = 2e18; 114 maxn[1] = -2e18, minn[1] = 2e18; 115 for(int i = 1; i <= len; i++) { 116 d[i] = read(); 117 if(fi != -2e18) 118 ans[0] = max(fi * d[i], ans[0]); 119 if(se != 2e18) 120 ans[0] = max(se * d[i], ans[0]); 121 fi = max(fi, d[i]), se = min(se, d[i]); 122 } 123 for(int i = 0; i <= len; i++) { 124 ans[i] = -2e18; 125 } 126 for(int i = len; i >= 1; i--) { 127 extend(s[i] - 'a', d[i]); 128 } 129 for(int i = 2; i <= tot; i++) { 130 addedge(t[i].fa, i); 131 } 132 DFS(1); 133 for(int i = len - 1; i >= 0; i--) { 134 num[i] += num[i + 1]; 135 ans[i] = max(ans[i], ans[i + 1]); 136 } 137 for(int i = 0; i < len; i++) { 138 if(num[i] == 0) { 139 printf("0 0\n"); 140 } else { 141 printf("%lld %lld\n", num[i], ans[i]); 142 } 143 } 144 return 0; 145 }