• BZOJ3238: [Ahoi2013]差异


    题解: 难点是如何求任意两个后缀的lcp 我们考虑到任意两个位置的后缀LCP取决于两者在SA中的最小值 因此我们有两种方法解决 首先对于sa数组按照h数组分治 统计每个位置的贡献 其次我们也可以单调栈找到每个位置前面第一个比他小的 和 后面第一个比他小的然后统计价值即可

    分治版本:

    /**************************************************************
        Problem: 3238
        User: wang9897
        Language: C++
        Result: Accepted
        Time:2968 ms
        Memory:19360 kb
    ****************************************************************/
     
    #include <bits/stdc++.h>
    #define N 500005
    #define INF 100000007
    #define ll long long
    using namespace std;
    int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return f*x;
    }
    char s[N];int sa[N],txt[N],rank1[N],t1[N],t2[N],rank2[N],td[N];
    bool cmp(int f[],int t,int w,int k){
        return f[t]==f[w]&&f[t+k]==f[w+k];
    }
    void Sa(char str[]){
        int len=strlen(str);
        int m=127;
        int *rank1=t2;int *td=t1;
        for(int i=0;i<m;i++) txt[i]=0;
        for(int i=0;i<len;i++){
            rank1[i]=str[i];txt[str[i]]++;
        }
        for(int i=1;i<m;i++) txt[i]+=txt[i-1];
        for(int i=len-1;i>=0;i--) sa[--txt[str[i]]]=i;
        for(int k=1;k<=len;k*=2){
            int p=0;
            for(int i=len-k;i<len;i++) td[p++]=i;
            for(int i=0;i<len;i++){
                if(sa[i]>=k) td[p++]=sa[i]-k;
            }
            for(int i=0;i<m;i++) txt[i]=0;
            for(int i=0;i<len;i++) txt[rank1[i]]++;
            for(int i=1;i<m;i++) txt[i]+=txt[i-1];
            for(int i=len-1;i>=0;i--) sa[--txt[rank1[td[i]]]]=td[i];
            swap(td,rank1);
            rank1[sa[0]]=0;
            p=1;
            for(int i=1;i<len;i++) rank1[sa[i]]=cmp(td,sa[i],sa[i-1],k)?p-1:p++;
            if(p==len) return ;
            m=p;
        }
    }
    int hh[N],height[N];
    void h(char str[]){
        int len=strlen(str);
        for(int i=0;i<len;i++) rank2[sa[i]]=i;
        memset(hh,0,sizeof(hh));
        for(int i=0;i<len;i++){
            if(rank2[i]==0) continue;
            int t=sa[rank2[i]-1];int w=i;int k;
            if(i==0||hh[i-1]<=1) k=0;
            else{
                k=hh[i-1]-1;t+=k;w+=k;
            }
            while(t<len&&w<len){
                if(str[t]==str[w]) k++;
                else break;
                t++;w++;
            }
            hh[i]=k;height[rank2[i]]=k;
        }
        return ;
    }
    ll ans,ans1,ans2;
    void fenzhi(int l,int r){
        if(l>r) return ;
    //  cout<<l<<" "<<r<<endl;
        ll t=INF;int tt;
        if(l==r){
            ans+=height[l];return ;
        }
        for(int i=l;i<=r;i++){
            if(height[i]<t){
                t=height[i];tt=i;
            }
        }
        ans+=1ll*(r-tt+1)*(tt-l+1)*t;
        fenzhi(l,tt-1);
        fenzhi(tt+1,r);
    }
    int main(){
        ios::sync_with_stdio(false);
        scanf(" %s",&s);int len=strlen(s);
        s[len]='$';
        Sa(s);h(s);
        ans=0;ans1=0;ans2=0;
        fenzhi(1,len);
        ans*=2;
        for(int i=len;i>=2;i--) ans1+=1ll*i*(i-1);
        for(int i=len-1;i>=1;i--) ans2+=1ll*(i+1)*i/2;
        printf("%lld
    ",ans1+ans2-ans);
        return 0;
    }
    

     单调栈:

    /**************************************************************
        Problem: 3238
        User: wang9897
        Language: C++
        Result: Accepted
        Time:5888 ms
        Memory:73216 kb
    ****************************************************************/
     
    #include <bits/stdc++.h>
    #define ll long long
    const int MAXN=5e5+10;
    using namespace std;
    int txt[MAXN],t1[MAXN],t2[MAXN],rank1[MAXN],rank2[MAXN],td[MAXN],sa[MAXN];
    bool cmp(int f[],int t,int w,int k){return f[t]==f[w]&&f[t+k]==f[k+w];}
    void Sa(char str[]){
        int len=strlen(str);int m=250;
        int *td=t1;int *rank1=t2;
        for(int i=0;i<m;i++)txt[i]=0;
        for(int i=0;i<len;i++)rank1[i]=str[i],txt[str[i]]++;
        for(int i=1;i<m;i++)txt[i]+=txt[i-1];
        for(int i=len-1;i>=0;i--)sa[--txt[str[i]]]=i;
        for(int k=1;k<=len;k*=2){
        int p=0;
        for(int i=len-k;i<len;i++)td[p++]=i;
        for(int i=0;i<len;i++)if(sa[i]>=k)td[p++]=sa[i]-k;
        for(int i=0;i<m;i++)txt[i]=0;
        for(int i=0;i<len;i++)txt[rank1[i]]++;
        for(int i=1;i<m;i++)txt[i]+=txt[i-1];
        for(int i=len-1;i>=0;i--)sa[--txt[rank1[td[i]]]]=td[i];
        swap(rank1,td);rank1[sa[0]]=0;p=1;
        for(int i=1;i<len;i++)rank1[sa[i]]=cmp(td,sa[i],sa[i-1],k)?p-1:p++;
        if(p==len)return ;
        m=p;
        }
    }
    int h[MAXN],H[MAXN];
    void hh(char str[]){
        int len=strlen(str);
        memset(h,0,sizeof(h));memset(H,0,sizeof(H));
        for(int i=0;i<len;i++)rank2[sa[i]]=i;
        for(int i=0;i<len;i++){
        if(!rank2[i])continue;
        int t=sa[rank2[i]-1];int w=i;int k=0;
        if(!i||H[i-1]<=1)k=0;
        else k=H[i-1]-1,t+=k,w+=k;
        while(t<len&&w<len){
            if(str[t]==str[w])k++;
            else break;
            t++;w++;
        }
        H[i]=k;h[rank2[i]]=k;
        }
    }
    int dp[MAXN][21],ma[MAXN];
    void St(char str[]){
        int len=strlen(str);
        ma[0]=-1;
        for(int i=1;i<MAXN;i++)if((i&(i-1))==0)ma[i]=ma[i-1]+1;else ma[i]=ma[i-1];
        for(int i=1;i<len;i++)dp[i][0]=h[i];
        for(int j=1;(1<<(j-1))<=len;j++){
        for(int i=1;i+(1<<j)<=len;i++){
            dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
        }
        }
    }
    int rmq(int l,int r){
        if(l>=r)return 0;
        l++;
        int k=ma[r-l+1];int k1=(1<<k);
        return min(dp[l][k],dp[r-k1+1][k]);
    }
    char s[MAXN];
    pair<int,int> st[MAXN];int tot;int rnum[MAXN],lnum[MAXN];
    vector<int>vec;
    int main(){
        scanf("%s",s);int len=strlen(s);s[len++]='$';
        Sa(s);hh(s);St(s);
      //  for(int i=1;i<len;i++)cout<<sa[i]<<" ";
      //  cout<<endl;
        for(int i=2;i<len;i++)vec.push_back(rmq(i-1,i));
        int sz=vec.size();
      //  for(int i=0;i<sz;i++)cout<<vec[i]<<" ";
      //  cout<<endl;
        for(int i=0;i<sz;i++){
        while(tot>0&&st[tot].first>vec[i]){tot--;}
        if(!tot)lnum[i]=i+1;
        else lnum[i]=i-st[tot].second;
    //  cout<<lnum[i]<<"::::";
        st[++tot]=make_pair(vec[i],i);
        }
      //  cout<<endl;
        reverse(vec.begin(),vec.end());tot=0;
        for(int i=0;i<sz;i++){
        while(tot>0&&st[tot].first>=vec[i]){tot--;}
        if(!tot)rnum[sz-i-1]=i+1;
        else rnum[sz-i-1]=i-st[tot].second;
        st[++tot]=make_pair(vec[i],i);
        }
        reverse(vec.begin(),vec.end());
        int n=len-1;
        ll ans=1ll*(n-1)*(n+1)*n/2;
        for(int i=0;i<sz;i++)ans-=1ll*2*lnum[i]*rnum[i]*vec[i];
        printf("%lld
    ",ans);
    }
    

    3238: [Ahoi2013]差异

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 4447  Solved: 2057
    [Submit][Status][Discuss]

    Description

    Input

    一行,一个字符串S

    Output

    一行,一个整数,表示所求值

    Sample Input

    cacao

    Sample Output


    54

    HINT



    2<=N<=500000,S由小写英文字母组成

  • 相关阅读:
    vulnhub靶场 之 DC -1
    PHP反序列化中过滤函数使用不当导致的对象注入
    网络内生安全试验场-CTF答题夺旗赛(第四季)web知识
    BUUCTF 随便注
    SWPUCTF 2019 web
    春秋-SQLi题
    i春秋-“百度杯”CTF比赛 十月场-Login
    i春秋-第三届“百越杯”福建省高校网络空间安全大赛-Do you know upload?
    i春秋CTF-“百度杯”CTF比赛 九月场 XSS平台
    终于等到你,最强 IDE Visual Studio 2017 正式版发布
  • 原文地址:https://www.cnblogs.com/wang9897/p/9426255.html
Copyright © 2020-2023  润新知