[SDOI2016]生成魔咒

渐渐感觉到省选难度的天差地别

题解:

前60是送给暴力的?

后面40分

首先其子串个数就不是能统计范围内的,所以hash或者trie已经挂了

那么就剩下后缀数组和自动机了(我不会啊)

考虑一下后缀数组。。

后缀数组原本答案等于总的子串-sigma(height[i])

它每一次都是在末尾加入,其实也就是增加了一个前缀

所以 就可以改成一个前缀数组(其实就是把串翻转一下)

然后 其实就非常简单了。。

我们可以先把整个串的height搞出来

然后插入一个元素实际就是插入一个后缀

那么查找到它的前一个后缀和后一个后缀,用rmq查找他们之间的lcp

前驱后继显然是用splay维护的(因为不会set)

考前模板题。。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 110000
#define INF 5e8
ll sa[N],a[N],c[N],x[N],y[N],rank[N],height[N],ans2[N];
ll num2,root,n,m,bz[N][21],fa[N],leftson[N],rightson[N],data[N];
struct re{
  ll a,b;
}cc[N];
void get_sa(ll n,ll m)
{
   ll p=0,f=0;
   for (ll i=1;i<=m;i++) c[i]=0;
   for (ll i=1;i<=n;i++) c[x[i]=a[i]]++;
   for (ll i=1;i<=m;i++) c[i]+=c[i-1];
   for (ll i=n;i;i--) sa[c[x[i]]--]=i;
   for (ll i=1;i<=n&&p<=n;i<<=1)
   {
       p=0;
       for (ll j=n-i+1;j<=n;j++) y[++p]=j;
       for (ll j=1;j<=n;j++)
         if (sa[j]>i) y[++p]=sa[j]-i;
       for (ll j=1;j<=m;j++) c[j]=0;
       for (ll j=1;j<=n;j++) c[x[y[j]]]++;
       for (ll j=1;j<=m;j++) c[j]+=c[j-1];
       for (ll j=n;j;j--) sa[c[x[y[j]]]--]=y[j];
       swap(x,y); x[sa[1]]=1; p=2;
       for (ll j=2;j<=n;j++)
         x[sa[j]]=y[sa[j]]==y[sa[j-1]]&&y[sa[j]+i]==y[sa[j-1]+i]
         ?p-1:p++;
       m=p; 
   } 
   for (ll i=1;i<=n;i++) rank[sa[i]]=i;
   for (ll i=1;i<=n;i++)
   {
       ll j=sa[rank[i]-1];
       if (f) f--;
       while (a[i+f]==a[j+f]) f++;
       height[rank[i]]=f;
   }
   for (ll i=1;i<=n;i++) bz[i][0]=height[i];
   for (ll i=1;i<=20;i++)
     for (ll j=1;j<=n;j++)
       if (j+(1<<i)-1<=n)
         bz[j][i]=min(bz[j][i-1],bz[j+(1<<(i-1))][i-1]);
} 
ll lcp(ll a,ll b)
{
   ll x=rank[a],y=rank[b];
   if (x>y) swap(x,y); x++;
   ll z=log2(y-x+1);
   return (min(bz[x][z],bz[y-(1<<z)+1][z]));
}
void rotate(ll x,ll y)
{
   ll father=fa[x];
   if (y==1)
   {
       rightson[father]=leftson[x];
       if (leftson[x]) fa[leftson[x]]=father;
   } else
   {
       leftson[father]=rightson[x];
       if (rightson[x]) fa[rightson[x]]=father;
   }
   fa[x]=fa[father];
   if (fa[x])
   {
     if (leftson[fa[x]]==father) leftson[fa[x]]=x;
     else rightson[fa[x]]=x;
   }
   fa[father]=x;
   if (y==1) leftson[x]=father; else rightson[x]=father;
   //updata(father); updata(x);
}
void splay(ll x,ll goal)
{
  if (x==root) return;
  ll father=fa[x];
  while (father!=goal)
  {
    if (fa[father]==goal)
    {
      if (x==leftson[father]) rotate(x,2); else rotate(x,1);
    } else
    {
      if (leftson[fa[father]]==father)
        if (leftson[father]==x)
          rotate(father,2),rotate(x,2);
        else rotate(x,1),rotate(x,2);
      else if (rightson[father]==x)
          rotate(father,1),rotate(x,1);
        else rotate(x,2),rotate(x,1);
    }
    father=fa[x];
  }
  if (goal==0) root=x;
}
void insert(ll x)
{
  ll y=root;
  while (y)
  {
    //count2[y]++;
    if (x<data[y])
    {
        if (!leftson[y]) break;
        y=leftson[y];
    } else
    {
        if (!rightson[y]) break;
        y=rightson[y];
    }
  }
  data[++num2]=x; fa[num2]=y;
  if (x>data[y]) rightson[y]=num2;
  else leftson[y]=num2;
  splay(num2,0);
}
ll pre(ll x)
{
  ll y=root,maxn=-INF;
  while (y)
  {
    if (data[y]<=x) maxn=max(maxn,data[y]);
    if (data[y]<=x) y=rightson[y];
    else y=leftson[y];
  }
  return maxn;
}
ll succ(ll x)
{
  ll y=root,minn=INF;
  while (y)
  {
    if (data[y]>=x) minn=min(minn,data[y]);
    if (data[y]<=x) y=rightson[y];
    else y=leftson[y];
  }
  return minn;
}
bool cmp(re x,re y)
{
   return(x.a<y.a);
}
int main()
{
    cin>>n;
    for (ll i=1;i<=n;i++)
    {
      cin>>cc[i].a;
      cc[i].b=n-i+1;
    }
    sort(cc+1,cc+n+1,cmp);
    cc[0].a=-INF; ll sum=0;
    for (ll i=1;i<=n;i++)
    {
      if (cc[i].a!=cc[i-1].a) sum++;
      a[cc[i].b]=sum;
    }
    get_sa(n,n);
    ll ans=0;
    for (ll i=1;i<=n;i++)
    {
       ll x=n-i+1;
       ll x1=pre(rank[x]),x2=succ(rank[x]);
       if (x1!=-INF) x1=sa[x1],ans+=ans2[x]=lcp(x1,x);
       if (x2!=INF) x2=sa[x2],ans-=ans2[x2],ans+=ans2[x2]=lcp(x,x2);
       cout<<i*(i+1)/2-ans<<endl; 
       insert(rank[x]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/yinwuxiao/p/8551689.html