【NOI2015】品酒大会 SAM
论没有看完题目的危害,以及预处理不做号的危害。两个小时过去了…………………………………………
不难。把字符串逆序建后缀自动机,利用fail边得到后缀树。(理解上的,实际上没有在树上跑。)
由于后缀树上每一个叶子节点所代表的串是原串的后缀。现在逆序之后,就变成了前缀。那
因为一个节点x的sz数组表示这个节点所代表的所有的串都出现了sz[x]次。而且该串所代表的字符串长度为 dep[fa[x]] + 1 ~ dep[x] 所以理论上考虑一个节点对答案的贡献是是要对 dep[fa[x]+1] ~ dep[x]都加一次的。但是很显然有前缀和的思想,那么就不用了。
总而言之。后缀自动机的思想就是用一个长串已有的信息,和它的后缀的信息汇总。进而得出全部的信息。
(特别地,对于任意的 1≤p,q≤n1≤p,q≤n,p≠qp≠q,第 pp 杯酒和第 qq杯酒都是“0相似”的。)不知道是否有人和我一样没看题。而且有些maxl,minl没初始化,WA了好久。心好累。
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define rep(i,j,k) for(register int i = j; i <= k; i++) 5 #define dow(i,j,k) for(register int i = j; i >= k; i--) 6 #define maxn 302333 7 #define ll long long 8 #define inf 0x7fffffff 9 using namespace std; 10 11 inline int read() { 12 int s = 0, t = 1; char c = getchar(); 13 while( !isdigit(c) ) { if( c == '-' ) t = -1; c = getchar(); } 14 while( isdigit(c) ) s = s * 10 + c - 48, c = getchar(); 15 return s * t; 16 } 17 18 int u, p, last = 1, tot = 1, v, nv, dep[maxn<<1], fa[maxn<<1], sz[maxn<<1]; 19 int maxl[maxn<<1][2], minl[maxn<<1][2], son[maxn<<1][26]; 20 inline void extend(int c,int key) { 21 u = last; last = p = ++tot; dep[p] = dep[u] + 1; sz[p] = 1; 22 maxl[p][0] = minl[p][0] = key; //cout<<"B "<<p<<" "<<key<<endl; 23 maxl[p][1] = -2e9; minl[p][1] = 2e9; 24 while( u && !son[u][c] ) son[u][c] = p, u = fa[u]; 25 if( !u ) fa[p] = 1; 26 else { 27 v = son[u][c]; 28 if( dep[v] == dep[u] + 1 ) fa[p] = v; 29 else { 30 nv = ++tot; dep[nv] = dep[u] + 1; 31 fa[nv] = fa[v]; fa[v] = fa[p] = nv; 32 maxl[tot][0] = maxl[tot][1] = -2e9; 33 minl[tot][0] = minl[tot][1] = 2e9; 34 memcpy(son[nv],son[v],sizeof(son[v])); 35 while( son[u][c] == v ) son[u][c] = nv, u = fa[u]; 36 } 37 } 38 } 39 40 int q[maxn<<1], tong[maxn<<1] = {0}, key[maxn]; 41 inline void pre() { 42 rep(i,1,tot) tong[dep[i]]++; 43 rep(i,1,tot) tong[i] += tong[i-1]; 44 dow(i,tot,1) q[tong[dep[i]]--] = i; 45 int x; 46 dow(i,tot,1) x = q[i], sz[fa[x]] += sz[x]; 47 dep[0] = -1; 48 } 49 ll cnt[maxn], ans[maxn]; char c[maxn]; 50 inline void updatemax(int x,int v) { 51 // cout<<"M "<<x<<" "<<v<<" "<<maxl[x][1]<<" "; 52 maxl[x][1] = max(maxl[x][1],v); 53 // cout<<maxl[x][1]<<endl; 54 if( maxl[x][1] > maxl[x][0] ) swap(maxl[x][1],maxl[x][0]); 55 } 56 inline void updatemin(int x,int v) { 57 // cout<<"I "<<x<<" "<<v<<" "<<minl[x][1]<<" "; 58 minl[x][1] = min(minl[x][1],v); 59 // cout<<minl[x][1]<<endl; 60 if( minl[x][1] < minl[x][0] ) swap(minl[x][1],minl[x][0]); 61 } 62 63 int main() { 64 int n = read(); scanf("%s", c+1); 65 maxl[1][0] = maxl[1][1] = -2e9; minl[1][0] = minl[1][1] = 2e9; 66 rep(i,1,n) key[i] = read(); 67 dow(i,n,1) extend(c[i]-'a',key[i]); 68 pre(); int x; 69 memset(ans,128,sizeof(ans)); 70 memset(cnt,0,sizeof(cnt)); 71 dow(i,tot,1) { 72 x = q[i]; 73 if( sz[x] > 1 ) { 74 cnt[dep[x]] += 1ll * (sz[x] - 1) * sz[x] / 2; 75 if( dep[fa[x]] >= 0 ) cnt[dep[fa[x]]] -= 1ll * (sz[x] - 1) * sz[x] / 2; 76 ans[dep[x]] = max(ans[dep[x]],max(1ll*maxl[x][0]*maxl[x][1],1ll*minl[x][0]*minl[x][1])); 77 } 78 updatemax(fa[x],maxl[x][0]); 79 updatemax(fa[x],maxl[x][1]); 80 updatemin(fa[x],minl[x][0]); 81 updatemin(fa[x],minl[x][1]); 82 } 83 dow(i,n-1,0) cnt[i] += cnt[i+1]; 84 dow(i,n-1,0) ans[i] = max(ans[i],ans[i+1]); 85 rep(i,0,n-1) if( !cnt[i] ) ans[i] = 0; 86 rep(i,0,n-1) printf("%lld %lld\n", cnt[i],ans[i]); 87 // x = read(); 88 return 0; 89 }
————————————————