• bzoj 3238


    明显要用求SA再求h,而lcp(i,j)就等于i到j之间最小的h

    用f[i]表示i跟比i大的后缀的lcp的和,然后用单调栈维护最小值就好了(有点像DP?)

     1 #include<bits/stdc++.h>
     2 #define inc(i,l,r) for(int i=l;i<=r;i++)
     3 #define dec(i,l,r) for(int i=l;i>=r;i--)
     4 #define link(x) for(edge *j=h[x];j;j=j->next)
     5 #define mem(a) memset(a,0,sizeof(a))
     6 #define inf 1e9
     7 #define ll long long
     8 #define succ(x) (1<<x)
     9 #define NM 500000+5
    10 using namespace std;
    11 int read(){
    12     int x=0,f=1;char ch=getchar();
    13     while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    14     while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    15     return x*f;
    16 }
    17 char st[NM];
    18 int n,m,tmp[NM],top[NM],rank[NM],sa[NM],h[NM];
    19 ll f[NM],ans;
    20 stack<int >s;
    21 void getsa(){
    22     int j;m=256;
    23     inc(i,0,n)top[rank[i]=(int)st[i]]++;
    24     inc(i,1,m)top[i]+=top[i-1];
    25     inc(i,0,n)sa[--top[rank[i]]]=i;
    26 //    inc(i,0,n)printf("%d ",sa[i]);printf("
    ");
    27     for(int k=1;k<=n;k<<=1){
    28         inc(i,0,n){
    29             j=sa[i]-k;
    30             if(j<0)j+=n+1;
    31             tmp[top[rank[j]]++]=j;
    32         }
    33 //        inc(i,0,n)printf("%d ",tmp[i]);printf("
    ");
    34         sa[tmp[top[0]=0]]=j=0;
    35         inc(i,1,n){
    36             if(rank[tmp[i-1]]!=rank[tmp[i]]||rank[tmp[i]+k]!=rank[tmp[i-1]+k])
    37             top[++j]=i;
    38             sa[tmp[i]]=j;
    39         }
    40         memcpy(rank,sa,sizeof(sa));
    41         memcpy(sa,tmp,sizeof(tmp));
    42         if(j>=n)break;
    43     }
    44     j=0;
    45 //    inc(i,0,n)printf("%d ",sa[i]);printf("
    ");
    46     inc(i,0,n)if(rank[i]){
    47         if(j)j--;
    48         while(st[i+j]==st[sa[rank[i]-1]+j])
    49         j++;
    50         h[rank[i]]=j;
    51     }
    52 //    inc(i,0,n)printf("%d ",h[i]);printf("
    ");
    53 }
    54 int main(){
    55     freopen("data.in","r",stdin);
    56     scanf("%s",st);
    57     n=strlen(st);st[n+1]='$';
    58     getsa();
    59     ans=(ll)(n+1)*(n-1)*n>>1;
    60     dec(i,n,0){
    61         while(!s.empty()&&h[s.top()]>h[i])s.pop();
    62         int t=s.empty()?n+1:s.top();
    63         f[i]=(ll)h[i]*(t-i)+f[t];
    64         ans-=f[i]<<1;s.push(i);
    65     }
    66 //    inc(i,0,n)printf("%lld ",f[i]);printf("
    ");
    67     printf("%lld",ans);
    68     return 0;
    69 }
    View Code
  • 相关阅读:
    ubuntu密码正确,却不能登录图形界面
    【转】ubuntu右键在当前位置打开终端
    一些值得学习的Unity教程 (很实用的包括源码)
    Git 报错:git
    Unity3D面试——真实的面试,unity3d面试
    拖拽以及常用的鼠标事件
    白话经典算法系列之一 冒泡排序的三种实现
    c#封装三维向量,另外也看了下别人的C++封装
    c#面试3(选择题)
    Unity3D中目标相对自身的前后左右方位判断
  • 原文地址:https://www.cnblogs.com/onlyRP/p/5186498.html
Copyright © 2020-2023  润新知