BZOJ4516: [Sdoi2016]生成魔咒
Description
魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示。
例如可以将魔咒字符 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 共有多少种生成魔咒。
Input
第一行一个整数 n。
第二行 n 个数,第 i 个数表示第 i 次操作加入的魔咒字符。
1≤n≤100000。
用来表示魔咒字符的数字 x 满足 1≤x≤10^9
Output
输出 n 行,每行一个数。第 i 行的数表示第 i 次操作后 S 的生成魔咒数量
Sample Input
7
1 2 3 3 3 1 2
1 2 3 3 3 1 2
Sample Output
1
3
6
9
12
17
22
3
6
9
12
17
22
题解Here!
据说这题可以被$SAM$秒杀,然而本蒟蒻只会$SA$。。。
题目要求出每一个前缀本质不同的后缀的个数。
那么我们可以把原序列倒过来,然后实际上就是对于每一个后缀求与其它后缀不重复的前缀个数,也即是后缀长度减去$height$。
求出某一个后缀对答案的贡献之后,他不应该停留在元序列中对后续答案的求解产生影响,所以应该把它删除。
这个可以用平衡树来完成。
但是考虑到每一个位置只与前后有关,我们可以用链表来代替。
还有,要离散化。。。
附代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #define MAXN 100010 using namespace std; int n; int val[MAXN],num[MAXN],SBT_front[MAXN],SBT_next[MAXN]; long long ans[MAXN]; int top,sa[MAXN],rk[MAXN],height[MAXN],tax[MAXN],tp[MAXN]; inline int read(){ int date=0,w=1; char c=0; while (c< '0' ||c> '9' ){ if (c== '-' )w=-1;c= getchar ();} while (c>= '0' &&c<= '9' ){date=date*10+c- '0' ;c= getchar ();} return date*w; } void radixsort(){ for ( int i=0;i<=top;i++)tax[i]=0; for ( int i=1;i<=n;i++)tax[rk[i]]++; for ( int i=1;i<=top;i++)tax[i]+=tax[i-1]; for ( int i=n;i>=1;i--)sa[tax[rk[tp[i]]]--]=tp[i]; } void suffixsort( int x){ top=x; for ( int i=1;i<=n;i++){ rk[i]=val[i]; tp[i]=i; } radixsort(); for ( int w=1,p=0;p<n;top=p,w<<=1){ p=0; for ( int i=1;i<=w;i++)tp[++p]=n-w+i; for ( int i=1;i<=n;i++) if (sa[i]>w)tp[++p]=sa[i]-w; radixsort(); swap(tp,rk); rk[sa[1]]=p=1; for ( int i=2;i<=n;i++) rk[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w])?p:++p; } } void getheight(){ for ( int i=1,j,k=0;i<=n;i++){ if (k)k--; j=sa[rk[i]-1]; while (val[i+k]==val[j+k])k++; height[rk[i]]=k; } } void work(){ for ( int i=1;i<=n;i++){ SBT_front[i]=i-1; SBT_next[i]=i+1; } for ( int i=1;i<=n;i++){ int now=n-i+1-max(height[rk[i]],height[SBT_next[rk[i]]]); ans[i]=( long long )now; height[SBT_next[rk[i]]]=min(height[rk[i]],height[SBT_next[rk[i]]]); height[rk[i]]=0; if (rk[i]!=1)SBT_next[SBT_front[rk[i]]]=SBT_next[rk[i]]; SBT_front[SBT_next[rk[i]]]=SBT_front[rk[i]]; } for ( int i=n;i>=1;i--)ans[i]+=ans[i+1]; for ( int i=n;i>=1;i--) printf ( "%lld\n" ,ans[i]); } void init(){ n=read(); for ( int i=1;i<=n;i++)num[i]=val[n-i+1]=read(); sort(num+1,num+n+1); int k=unique(num+1,num+n+1)-num-1; for ( int i=1;i<=n;i++)val[i]=lower_bound(num+1,num+k+1,val[i])-num; suffixsort(k+1); getheight(); } int main(){ init(); work(); return 0; } |
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步