[SDOI2016]生成魔咒

题目描述

魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示。例如可以将魔咒字符 1、2 拼凑起来形成一个魔咒串 [1,2]。

一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒。

例如 S=[1,2,1] 时,它的生成魔咒有 [1]、[2]、[1,2]、[2,1]、[1,2,1] 五种。S=[1,1,1] 时,它的生成魔咒有 [1]、[1,1]、[1,1,1] 三种。最初 S 为空串。共进行 n 次操作,每次操作是在 S 的结尾加入一个魔咒字符。每次操作后都需要求出,当前的魔咒串 S 共有多少种生成魔咒。

输入输出格式

输入格式:

第一行一个整数 n。

第二行 n 个数,第 i 个数表示第 i 次操作加入的魔咒字符。

输出格式:

输出 n 行,每行一个数。第 i 行的数表示第 i 次操作后 S 的生成魔咒数量

输入输出样例

输入样例#1: 复制
7
1 2 3 3 3 1 2
输出样例#1: 复制
1
3
6
9
12
17
22

说明

对于%10的数据,1≤n≤101 \le n \le 101n10

对于%30的数据,1≤n≤1001 \le n \le 1001n100

对于%60的数据,1≤n≤1001 \le n \le 1001n100

对于%100的数据,1≤n≤1000001 \le n \le 1000001n100000

用来表示魔咒字符的数字 x 满足1≤n≤1091 \le n \le 10^91n109

反转字符串,这样就变成了后缀

先后缀数组求出height数组

然后从前往后一个一个加

首先我们知道一个字符串的字串数是每个后缀的长度减去height[i]

每加入一个字符,就新产生一个后缀

那么每添加一个前缀,增加了多少个不同的子串,其实就是在之前添加的前缀中

排名最靠近该前缀的两个串a和b,计算出他们与该前缀的lcp,

然后不同的子串数就是当前添加的前缀长度len-max(lcpa,lcpb)了

找排名最靠近的用线段树

以后模板改了,从1开始,方便很多

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cmath>
  5 #include<cstring>
  6 #include<set>
  7 using namespace std;
  8 typedef long long lol;
  9 int n,m,c[100001],x[100001],y[100001],SA[100001],s[100001],b[100001],rank[100001],h[100001];
 10 int Mx[400001],Mi[400001],Log[100001],Min[100001][21];
 11 lol ans;
 12 void radix_sort()
 13 {int i;
 14   for (i=0;i<=m;i++)
 15     c[i]=0;
 16   for (i=1;i<=n;i++)
 17     c[x[y[i]]]++;
 18   for (i=2;i<=m;i++)
 19     c[i]+=c[i-1];
 20   for (i=n;i>=1;i--)
 21     SA[c[x[y[i]]]--]=y[i];
 22 }
 23 void build_SA()
 24 {int i,j,k,p;
 25   for (i=1;i<=n;i++)
 26     x[i]=s[i],y[i]=i;
 27   m=100000;
 28   radix_sort();
 29   for (k=1;k<=n;k<<=1)
 30     {
 31       p=0;
 32       for (i=n-k+1;i<=n;i++)
 33     y[++p]=i;
 34       for (i=1;i<=n;i++)
 35     if (SA[i]>k) y[++p]=SA[i]-k;
 36       radix_sort();
 37       p=1;swap(x,y);
 38       x[SA[1]]=1;
 39       for (i=2;i<=n;i++)
 40     x[SA[i]]=((y[SA[i]]==y[SA[i-1]])&&(y[SA[i]+k]==y[SA[i-1]+k]))?p:++p;
 41       if (p>=n) break;
 42       m=p;
 43     }
 44   for (i=1;i<=n;i++)
 45     rank[SA[i]]=i;
 46   int L=0;
 47   for (i=1;i<=n;i++)
 48     {
 49       if (L>0) L--;
 50       j=SA[rank[i]-1];
 51       while (i+L<=n&&j+L<=n&&(s[j+L]==s[i+L])) L++;
 52       h[rank[i]]=L;
 53     }
 54 }
 55 void update(int rt,int l,int r,int x)
 56 {
 57   if (l==r)
 58     {
 59       Mx[rt]=Mi[rt]=x;
 60       return;
 61     }
 62   int mid=(l+r)/2;
 63   if (x<=mid) update(rt<<1,l,mid,x);
 64   else update(rt<<1|1,mid+1,r,x);
 65   Mx[rt]=max(Mx[rt<<1],Mx[rt<<1|1]);
 66   Mi[rt]=min(Mi[rt<<1],Mi[rt<<1|1]);
 67 }
 68 int query(int rt,int l,int r,int L,int R,int p)
 69 {
 70   if (l>=L&&r<=R)
 71     {
 72       if (p==1)
 73     return Mx[rt];
 74       else return Mi[rt];
 75     }
 76   int mid=(l+r)/2,mx=0,mi=n+1;
 77   if (p==1)
 78     {
 79       if (L<=mid) mx=max(mx,query(rt<<1,l,mid,L,R,p));
 80       if (R>mid) mx=max(mx,query(rt<<1|1,mid+1,r,L,R,p));
 81       return mx;
 82     }
 83   else
 84     {
 85       if (L<=mid) mi=min(mi,query(rt<<1,l,mid,L,R,p));
 86       if (R>mid) mi=min(mi,query(rt<<1|1,mid+1,r,L,R,p));
 87       return mi;
 88     }
 89 }
 90 int RMQ(int x,int y)
 91 {
 92   int L=Log[y-x+1];
 93   return min(Min[x][L],Min[y-(1<<L)+1][L]);
 94 }
 95 int main()
 96 {int i,tot,j,tmp;
 97   //freopen("zyys.out","w",stdout);
 98   scanf("%d",&n);
 99   for (i=1;i<=n;i++)
100     {
101       scanf("%d",&s[n-i+1]);
102       b[i]=s[n-i+1];
103     }
104   sort(b+1,b+n+1);
105   tot=unique(b+1,b+n+1)-b-1;
106   for (i=1;i<=n;i++)
107     s[i]=lower_bound(b+1,b+tot+1,s[i])-b;
108   build_SA();
109   Log[1]=0;
110   for (i=2;i<=n;i++)
111     Log[i]=Log[i/2]+1;
112   for (i=1;i<=n;i++)
113     Min[i][0]=h[i];
114   for (j=1;(1<<j)<=n;j++)
115     {
116       for (i=1;i<=n-(1<<j)+1;i++)
117     Min[i][j]=min(Min[i][j-1],Min[i+(1<<j-1)][j-1]);
118     }
119   memset(Mx,-127/2,sizeof(Mx));memset(Mi,127/2,sizeof(Mi));
120   update(1,0,n+1,0);update(1,0,n+1,n+1);
121   for (i=n;i>=1;i--)
122     {
123       int now=rank[i];
124       int pre=query(1,0,n+1,0,now-1,1),nxt=query(1,0,n+1,now+1,n+1,2);
125       tmp=0;
126       if (pre>=1)
127       tmp=max(tmp,RMQ(pre+1,now));
128       if (nxt<=n)
129       tmp=max(tmp,RMQ(now+1,nxt));
130       ans+=n-i+1-tmp;
131       printf("%lld\n",ans);
132       update(1,0,n+1,now);
133     }
134 }

 

posted @ 2018-03-05 16:22  Z-Y-Y-S  阅读(314)  评论(4编辑  收藏  举报