牛客网暑期ACM多校训练营(第一场)I.Substring(SA|后缀数组)

                                              I.Substring

传送门

题意:找出最大的集合内串互不同构的子串的集合的大小.

因为串内字符只存在a,b,c,

所以我们暴力处理出原串的所有同构串,并重构一个包含原串所有同构的新串,新串的长度为原串的长度len*6

那么对于这个问题就转化成了计算新串中不同的子串的个数,这个问题用SA或是SAM都可以解决

由于蒟蒻只会SA,下面的代码上的就是SA解题版.

在我们算出的不同(SA算出的是不同的子串,不是不同构!)的子串的中有两种串

第一类形如


aaaaaaaaa


只存在a,b,c中的一种字符

除此以外的串都算作第二类

显然可知,对于第一类串,同构的串存在3种,而对于第二类串,同构的串存在6

我们定义不同的串的个数为s_{mul},第一类串的个数为s_{sg}

那么显然便可以得到我们所要的结果

                                                              ans=\frac{(s_{mul}-s_{sg})}{6}+\frac{s_{sg}}{3}=\frac{(s_{mul}+s_{sg})}{6}

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#include<set>
#include<queue>
#include<limits.h>
#include<string.h>
#include<map>
#include<list>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long long LL;

#define inf int(0x3f3f3f3f)
#define mod ll(1e9+7)
#define eps double(1e-7)
#define pi acos(-1.0)
#define lson  root << 1
#define rson  root << 1 | 1

#define maxn 50005*6
#define rank Rank

int n,pos;
int tot;
ll wa[maxn],wb[maxn],wsf[maxn],wv[maxn],sa[maxn];
ll rank[maxn],height[maxn],s[maxn];
char str[maxn];

bool cmp(ll *r,int a,int b,int k)
{
    return r[a]==r[b]&&r[a+k]==r[b+k];
}

void get_sa(ll *r,ll *sa,int n,int m)
{
    ll i,j,p,*x=wa,*y=wb,*t;
    for(i=0; i<m; i++)
        wsf[i]=0;
    for(i=0; i<n; i++)
        wsf[x[i]=r[i]]++;
    for(i=1; i<m; i++)
        wsf[i]+=wsf[i-1];
    for(i=n-1; i>=0; i--)
        sa[--wsf[x[i]]]=i;
    p=1;
    j=1;
    for(; p<n; j*=2,m=p)
    {
        for(p=0,i=n-j; i<n; i++)
            y[p++]=i;
        for(i=0; i<n; i++)
            if(sa[i]>=j)
                y[p++]=sa[i]-j;
        for(i=0; i<n; i++)
            wv[i]=x[y[i]];
        for(i=0; i<m; i++)
            wsf[i]=0;
        for(i=0; i<n; i++)
            wsf[wv[i]]++;
        for(i=1; i<m; i++)
            wsf[i]+=wsf[i-1];
        for(i=n-1; i>=0; i--)
            sa[--wsf[wv[i]]]=y[i];
        t=x;
        x=y;
        y=t;
        x[sa[0]]=0;
        for(p=1,i=1; i<n; i++)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++;
    }
}


void get_height(ll *r,int n)
{
    int i,j,k=0;
    for(i=0; i<n; i++)
        rank[sa[i]]=i;
    for(i=0; i<n; i++)
    {
        if(k)
            k--;
        else
            k=0;
        j=sa[rank[i]-1];
        while(r[i+k]==r[j+k])
            k++;
        height[rank[i]]=k;
    }
}

ll cal_s_mul()
{
    ll ans=0;
    ll pre=0;
    for(int i=0; i<pos; i++)
    {
        ans+=n-(sa[i]%(n+1))-min(height[i],min(pre,n-(sa[i]%(n+1))));
        pre=n-(sa[i]%(n+1));
    }
    return ans;
}

ll cal_s_sg()
{
    ll ans=0;
    ll cnt=1;
    for(int i=1;i<n;i++)
    {
        if(str[i]!=str[i-1])
            ans=max(ans,cnt),cnt=1;
        else
            cnt++;
    }
    ans=max(ans,cnt);
    return ans*3ll;
}

void ex_to(int a,int b,int c)
{
    for(int i=0; i<n; i++)
    {
        if(str[i]=='a')
            s[pos++]=a;
        else if(str[i]=='b')
            s[pos++]=b;
        else
            s[pos++]=c;
    }
    s[pos++]=0;
}

void op()
{
    int ss[5];
    for(int i=0; i<3; i++)
        ss[i]=i+1;
    pos=0;
    do
    {
        ex_to(ss[0],ss[1],ss[2]);
    }
    while(next_permutation(ss,ss+3));
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    while(cin>>n)
    {
        cin>>str;
        op();
        get_sa(s,sa,pos,130);
        get_height(s,pos);
        ll ans=cal_s_mul();
        ans=(ans-cal_s_sg())/6ll+cal_s_sg()/3ll;
        cout<<ans<<endl;
    }
}

猜你喜欢

转载自blog.csdn.net/Murphyc/article/details/81141184