BZOJ 4199: [Noi2015]品酒大会 后缀自动机+逆序更新
一道裸题,可以考虑自底向上去更新方案数与最大值。
没啥难的
细节........
Code:
#include <cstdio> #include <algorithm> #include <cstring> #define setIO(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) #define maxn 1000006 #define inf -0x3f3f3f3f3f3f3f3fll #define ll long long using namespace std; int n,is[maxn],appear[maxn]; long long val[maxn],ans1[maxn],ans2[maxn],maxv[maxn],minv[maxn]; char str[maxn]; // struct Graph{ // int head[maxn],to[maxn],nex[maxn],edges; // void addedge(int u,int v) { nex[++edges] = head[u],head[u] = edges,to[edges] = v; } // }G; struct SAM{ int f[maxn],cnt[maxn],ch[maxn][30],len[maxn],tot,last; int C[maxn],rk[maxn]; void init() { tot = last = 1; for(int i = 0;i < maxn; ++i) ans2[i] = inf; } void ins(int c,int cur){ int np = ++tot,p = last; len[np] = len[last] + 1, last = tot; while(p && !ch[p][c]) ch[p][c] = np,p = f[p]; if(!p) f[np] = 1; else{ int q = ch[p][c]; if(len[q] == len[p] + 1) f[np] = q; else { int nq = ++tot; len[nq] = len[p] + 1; is[nq] = 1; memcpy(ch[nq],ch[q],sizeof(ch[q])); f[nq] = f[q],f[q] = f[np] = nq; while(p && ch[p][c] == q) ch[p][c] = nq,p = f[p]; } } ++cnt[last]; maxv[last] = val[cur]; minv[last] = val[cur]; } void build(){ for(int i = 1;i <= tot; ++i) ++C[len[i]]; for(int i = 1;i <= tot; ++i) C[i] += C[i - 1]; for(int i = 1;i <= tot; ++i) rk[C[len[i]]--] = i; for(int i = tot;i >= 1; --i) { int p = rk[i]; ans1[len[f[p]]] += (long long)cnt[f[p]] * cnt[p]; cnt[f[p]] += cnt[p]; if(is[f[p]] && !appear[f[p]]) { appear[f[p]] = 1; minv[f[p]] = minv[p]; maxv[f[p]] = maxv[p]; continue; } ans2[len[f[p]]] = max(ans2[len[f[p]]],maxv[p]*maxv[f[p]]); ans2[len[f[p]]] = max(ans2[len[f[p]]],minv[p]*minv[f[p]]); maxv[f[p]] = max(maxv[f[p]],maxv[p]); minv[f[p]] = min(minv[f[p]],minv[p]); } } }sam; int main(){ // setIO("input"); scanf("%d",&n),scanf("%s",str),sam.init(); for(int i = 0;i < n; ++i) scanf("%lld",&val[i]); for(int i = n - 1;i >= 0; --i) sam.ins(str[i] - 'a',i); sam.build(); for(int i = n - 1;i >= 0; --i) { ans1[i] += ans1[i + 1]; ans2[i] = max(ans2[i],ans2[i+1]); } for(int i = 0;i < n; ++i) { if(!ans1[i]) printf("%d %d\n",0,0); else printf("%lld %lld\n",ans1[i],ans2[i]); } return 0; }