[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 的生成魔咒数量
输入输出样例
说明
对于%10的数据,1≤n≤101 \le n \le 101≤n≤10
对于%30的数据,1≤n≤1001 \le n \le 1001≤n≤100
对于%60的数据,1≤n≤1001 \le n \le 1001≤n≤100
对于%100的数据,1≤n≤1000001 \le n \le 1000001≤n≤100000
用来表示魔咒字符的数字 x 满足1≤n≤1091 \le n \le 10^91≤n≤109
反转字符串,这样就变成了后缀
先后缀数组求出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 }