[LGP5115] Check,Check,Check one two!

Keywords: PHP

The magic way of thinking, or to learn one.

Question meaning: give you a string and define lcs with two prefixes and lcp with two suffixes. Find the value of the formula sub membrane \ (2 ^ {64} \).
\[ \sum_{1\le i<j\le n} lcp(i,j)lcs(i,j)[lcp(i,j)\le k1][lcs(i,j)\le k2] \]
Analysis:

For a pair of \ (< I, J > \), let's put their lcs and lcp together, and we can see that
\[ s[i-lcs(i,j)+1,i+lcp(i,j)-1]=s[j-lcs(i,j)+1,j+lcp(i,j)-1]\\ s[i-lcs(i,j)]\not=s[j-lcs(i,j)]\\ s[i+lcp(i,j)]\not=s[j+lcp(i,j)]\\ \]
This inspires us to find all substring pairs \ (< I, J, len > \) that meet the following conditions.
\[ s[i,i+len-1]=s[j,j+len-1],s[i-1]\not=s[j-1],s[i+len]\not=s[j+len] \]
We can know that its contribution is
\[ \sum_{\max(1,len-k2+1)}^{\min(len,k1)} k(len-k+1)=\sum_{k=1}^{min(len,k1)}k(len-k+1)-\sum_{k=1}^{\max(0,len-k2)}k(len-k+1) \]
Consider creating a SA and recording the first character of the suffix.

Heuristics merge from high to low on the height array and count the answers at the same time.

#include <bits/stdc++.h>
#define ull unsigned long long 
using namespace std;

const int N=1e5+10;

int n,k1,k2;
char s[N];
int sa[N],ht[N],rc[N],c[N];
int lp[N],rp[N],bl[N],siz[N],cnt[N][26];

void buildSa() {
    int *x=ht,*y=rc,i,p,k,m=128;
    for(i=0; i<=m; ++i) c[i]=0;
    for(i=1; i<=n; ++i) c[x[i]=s[i]]++;
    for(i=1; i<=m; ++i) c[i]+=c[i-1];
    for(i=n; i>=1; --i) sa[c[x[i]]--]=i;
    for(k=1; k<n; k<<=1) {
        for(i=n-k+1,p=0; i<=n; ++i) y[++p]=i;
        for(i=1; i<=n; ++i) if(sa[i]>k) y[++p]=sa[i]-k;
        for(i=0; i<=m; ++i) c[i]=0;
        for(i=1; i<=n; ++i) c[x[y[i]]]++;
        for(i=1; i<=m; ++i) c[i]+=c[i-1];
        for(i=n; i>=1; --i) sa[c[x[y[i]]]--]=y[i];
        swap(x,y), x[sa[1]]=p=1;
        for(i=2; i<=n; ++i) x[sa[i]]=
            y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p:++p;
        if((m=p)>=n) break;
    }
    for(i=1; i<=n; ++i) rc[sa[i]]=i;
    for(i=1,k=0; i<=n; ++i) {
        p=sa[rc[i]-1]; if(k) k--;
        while(s[i+k]==s[p+k]) ++k;
        ht[rc[i]]=k;
    }
//  for(int i=1; i<=n; ++i) {
//      cout<<(s+sa[i]);
//      if(i>1) cout<<" "<<ht[i];
//      cout<<endl;
//  }
}

pair<int,int> h[N];
ull sm(int x) {return (ull)x*(x+1)/2;}
ull ssm(int x) {return (ull)x*(2*x+1)*(x+1)/6;}
ull F(int x) {
    if(x>=k1+k2) return 0;
    ull s1=(ull)(x+1)*sm(min(x,k1))-ssm(min(x,k1));
    ull s2=(ull)(x+1)*sm(max(0,x-k2))-ssm(max(0,x-k2));
    return s1-s2;
}
ull f[N];
ull calc(int x,int y) {
    ull res=(ull)siz[x]*siz[y];
    for(int i=0; i<26; ++i) res-=(ull)cnt[x][i]*cnt[y][i];
    return res;
}
void merge(int x,int y) {
    for(int i=0; i<26; ++i) cnt[y][i]+=cnt[x][i];
    for(int i=lp[x]; i<=rp[x]; ++i) bl[i]=y;
    lp[y]=min(lp[y],lp[x]);
    rp[y]=max(rp[y],rp[x]);
    siz[y]+=siz[x];
}

int main() {
    scanf("%s%d%d",s+1,&k1,&k2);
    n=strlen(s+1);
    k1=min(k1,n);
    k2=min(k2,n);
    for(int i=1; i<=n; ++i) f[i]=F(i);
    buildSa();
    for(int i=1; i<=n; ++i) {
        lp[i]=rp[i]=bl[i]=i; siz[i]=1;
        if(sa[i]>1) cnt[i][s[sa[i]-1]-'a']++;
    }
    for(int i=2; i<=n; ++i) 
        h[i-1]=make_pair(-ht[i],i);
    sort(h+1,h+n);
    ull ans=0;
    for(int i=1; i<n; ++i) {
        int len=-h[i].first;
        int x=bl[h[i].second];
        int y=bl[h[i].second-1];
        if(siz[x]>siz[y]) swap(x,y);
        ans+=(ull)f[len]*calc(x,y);
        merge(x,y);
//      printf("%d,%d,%d,(%llu)\n",len,x,y,ans);
    }
    printf("%llu\n",ans);
    return 0;
}

Posted by Tremour on Mon, 28 Oct 2019 09:20:20 -0700