• 【BZOJ3238】【AHOI2013】差异


    sam好,好写好调好ac!

    原题:

    图片题面好评

    2<=N<=500000

    在syq大神的指点下终于理解一道后缀自动姬了quq

    (其实是因为这道题的dp主要是在后缀树(就是拓扑序)上搞树形dp……

    恩sam有个好玩的东西呢就是搞出后缀自动姬后根据max搞一个类似与后缀数组中countrank的东西

    这个就是自动姬的拓扑序,同时也是parent树的不知道什么序,反正如果倒叙遍历这个序列的话x一定会比father[x]先访问到就对了

    然后就可以直接用countrank搞树形dp辣

    每个树点对答案的贡献就是(max[x]-max[father[x]])*C_{|right[x]|}^{2}

    写到这里我突然发现这个组合数不太理解啊,如果两个节点在同一个子节点的子树中怎么办……

    一定是还有什么性质我没考虑到

    syq回寝吃泡面了,只能回去问syq了quq

    啊,syq吃完泡面后讲明白了quq

    就像下面酱紫一个图:

    在这个后缀树中,现在计算2节点对于答案的贡献

    我本来的想法是如果直接用2的深度乘C_{子树大小}^{2}岂不是会出现两个节点在同一子节点的子树中然后重复计算的情况?
    但是实际上在计算贡献的时候是用(max[x]-max[father[x]])乘组合数的,这个表示的是2和1之间的连边,而不是2的深度

    2和1对答案的贡献显然就乘C_{子树大小}^{2}

    这样就解决了Σlcp(i,j)*2的问题,至于前面那些东西,最后结果是(n+1)*(n-1)*n/2,请同学们自行推到 _(:3 」∠)_

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 using namespace std;
     7 #define ll long long
     8 int rd(){int z=0,mk=1;  char ch=getchar();
     9     while(ch<'0'||ch>'9'){if(ch=='-')mk=-1;  ch=getchar();}
    10     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
    11     return z*mk;
    12 }
    13 char s[510000];  int n;
    14 int nxt[1100000][26],fa[1100000],mx[1100000],sz[1100000],sm[1100000];
    15 int lst=1,tt=1;
    16 int cnt[1100000],cntrk[1100000];
    17 void ist(int x){
    18     int p=lst,np=lst=++tt;
    19     mx[np]=mx[p]+1;  sz[np]=sm[np]=1;
    20     while(!nxt[p][x] && p)  nxt[p][x]=np,p=fa[p];
    21     if(!p)  fa[np]=1;
    22     else{
    23         int q=nxt[p][x];
    24         if(mx[p]+1==mx[q])  fa[np]=q;
    25         else{
    26             int nq=++tt;  mx[nq]=mx[p]+1;
    27             memcpy(nxt[nq],nxt[q],sizeof(nxt[q]));
    28             fa[nq]=fa[q];  fa[q]=fa[np]=nq;
    29             while(nxt[p][x]==q)  nxt[p][x]=nq,p=fa[p];
    30         }
    31     }
    32 }
    33 void gtcntrk(){
    34     for(int i=1;i<=tt;++i)  ++cnt[mx[i]];
    35     for(int i=1;i<=n;++i)  cnt[i]+=cnt[i-1];
    36     for(int i=tt;i;--i)  cntrk[cnt[mx[i]]--]=i;
    37 }
    38 ll play(){
    39     ll bwl=0;
    40     for(int i=tt;i;--i){
    41         sz[fa[cntrk[i]]]+=sz[cntrk[i]];
    42         /*bwl+=(ll)sm[fa[cntrk[i]]]*sz[cntrk[i]]*mx[fa[cntrk[i]]];
    43         sm[fa[cntrk[i]]]+=sz[cntrk[i]];*/
    44         bwl+=(ll)(mx[cntrk[i]]-mx[fa[cntrk[i]]])*sz[cntrk[i]]*(sz[cntrk[i]]-1);
    45     }
    46     return bwl;
    47 }
    48 int main(){//freopen("ddd.in","r",stdin);
    49     scanf("%s",s+1);  n=strlen(s+1);
    50     for(int i=1;i<=n;++i)  ist(s[i]-'a');
    51     gtcntrk();
    52     cout<<(ll)(n+1)*n/2*(n-1)-play()<<endl;
    53     return 0;
    54 }
    View Code
  • 相关阅读:
    捡到一本<C++ Reference>
    题目1008:最短路径问题
    题目1014:排名
    题目1080:进制转换
    题目1081:递推数列
    题目1086:最小花费
    题目1076:N的阶乘
    题目1035:找出直系亲属
    在Mac上搭建Jenkins环境
    获取鼠标点击UGUI,先对于特定物体的相对坐标
  • 原文地址:https://www.cnblogs.com/JSL2018/p/6545370.html
Copyright © 2020-2023  润新知