• [BZOJ4199][Noi2015]品酒大会 树形DP+后缀自动机


    由于要找后缀的前缀,所以先用反串建立SAM。
    link边组成了后缀树。
    两个子串的最长公共前缀是LCA的step
    树形dp即可。
     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cstdlib>
     5 #include<cmath>
     6 #include<algorithm>
     7 #define maxn 1200000
     8 using namespace std;
     9 struct edge {
    10     int to,next;
    11 }e[maxn];
    12 int n,a[maxn];
    13 char s[maxn];
    14 int head[maxn],d;
    15 long long ans[maxn],mx[maxn],mn[maxn],sum[maxn];
    16 struct data {
    17     int last,cnt;
    18     int son[maxn][26],link[maxn],step[maxn],v[maxn],size[maxn];
    19     int tmp[maxn];
    20     data() {last=cnt=1;v[1]=2147483647;}
    21     void extend(int c,int val) {
    22         int p=last,np=last=++cnt;step[np]=step[p]+1;v[np]=val,size[np]=1;
    23         while(p&&!son[p][c]) son[p][c]=np,p=link[p];
    24         if(!p) link[np]=1;
    25         else {
    26             int q=son[p][c];
    27             if(step[q]==step[p]+1) link[np]=q;
    28             else {
    29                 int nq=++cnt;v[nq]=2147483647;
    30                 memcpy(son[nq],son[q],sizeof(son[q]));
    31                 link[nq]=link[q];
    32                 link[q]=link[np]=nq;
    33                 step[nq]=step[p]+1;
    34                 while(son[p][c]==q&&p) son[p][c]=nq,p=link[p];
    35             }
    36         }
    37     }
    38     void add(int u,int v) {e[d].next=head[u];e[d].to=v;head[u]=d++;}
    39     void build() {for(int i=1;i<=cnt;i++) add(link[i],i),ans[i]=-21474836470000000000000LL;}
    40     void query(int x) {
    41         mx[x]=-2147483647;mn[x]=2147483647;
    42         if(v[x]!=2147483647) mx[x]=mn[x]=v[x];
    43         for(int i=head[x];i>=0;i=e[i].next) {
    44             int to=e[i].to;
    45             query(to);
    46             if(mx[x]!=-2147483647&&mn[x]!=2147483647&&mx[to]!=-2147483647&&mn[to]!=2147483647) ans[step[x]]=max(ans[step[x]],max(mx[x]*mx[to],mn[to]*mn[x]));
    47             mx[x]=max(mx[x],mx[to]);mn[x]=min(mn[x],mn[to]);
    48             sum[step[x]]+=1LL*size[x]*size[to];size[x]+=size[to];
    49         }
    50         
    51     }
    52     void getans() {
    53         for(int i=n-1;i>=0;i--) sum[i]+=sum[i+1],ans[i]=max(ans[i],ans[i+1]); 
    54         for(int i=0;i<=n-1;i++) if(sum[i]) printf("%lld %lld
    ",sum[i],ans[i]); else printf("0 0
    ");
    55     }
    56     
    57 }sam;
    58 
    59 int main() {
    60     memset(head,-1,sizeof(head));
    61     scanf("%d",&n);
    62     scanf("%s",s+1);
    63     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    64     for(int i=n;i>=1;i--) sam.extend(s[i]-'a',a[i]);
    65     sam.build();
    66     sam.query(1);
    67     sam.getans();
    68     
    69 }
    View Code
    O(∩_∩)O~ (*^__^*) 嘻嘻…… O(∩_∩)O哈哈~
  • 相关阅读:
    大数据组件原理总结-Hadoop、Hbase、Kafka、Zookeeper、Spark
    淘宝搜索引擎的缓存机制入门总结
    Log4j写日志文件使用详解
    storm入门(一):storm编程框架与举例
    storm入门(二):关于storm中某一段时间内topN的计算入门
    关于京东推荐模型的阅读理解
    运维开发入门记录
    Redis 3.0.0 集群部署
    Redis集群部署
    秘籍
  • 原文地址:https://www.cnblogs.com/wls001/p/8260426.html
Copyright © 2020-2023  润新知