zoukankan      html  css  js  c++  java
  • [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
    

    Sample Output

    1
    3
    6
    9
    12
    17
    22
    

    Solution

    后缀数组。

    把原串(reverse)一下,建出后缀数组,求一下(height)数组。

    然后按后缀的字典序建一个链表,每次考虑把串第一个位置的后缀算出贡献,然后利用链表合并一下(height)就好了。

    最后倒序前缀和输出答案就行了。

    #include<bits/stdc++.h>
    using namespace std;
    
    #define ll long long 
    
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    void print(ll x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(ll x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    const int maxn = 1e6+10;
    const int inf = 1e9;
    
    int n,w[maxn],r[maxn];
    
    int spx[maxn],spy[maxn],sum[maxn],sa[maxn],rk[maxn],height[maxn],d[maxn][20],lg[maxn];
    
    void build() {
    	int m=n,p=0;int *x=spx,*y=spy;
    	for(int i=1;i<=n;i++) sum[x[i]=w[i]]++;
    	for(int i=1;i<=m;i++) sum[i]+=sum[i-1];
    	for(int i=n;i;i--) sa[sum[x[i]]--]=i;
    
    	for(int k=1,tot=0;p<n;k<<=1,tot=0) {
    		for(int i=n-k+1;i<=n;i++) y[++tot]=i;
    		for(int i=1;i<=n;i++) if(sa[i]>k) y[++tot]=sa[i]-k;
    
    		for(int i=1;i<=m;i++) sum[i]=0;
    		for(int i=1;i<=n;i++) sum[x[y[i]]]++;
    		for(int i=1;i<=m;i++) sum[i]+=sum[i-1];
    		for(int i=n;i;i--) sa[sum[x[y[i]]]--]=y[i];
    
    		swap(x,y),x[sa[1]]=p=1;
    		for(int i=2;i<=n;i++)
    			if(y[sa[i]]!=y[sa[i-1]]||y[sa[i]+k]!=y[sa[i-1]+k]) x[sa[i]]=++p;
    			else x[sa[i]]=p;
    		m=p;
    	}
    
    	for(int i=1;i<=n;i++) rk[sa[i]]=i;p=1;
    	for(int i=1;i<=n;i++) {
    		if(p) p--;
    		while(w[i+p]==w[sa[rk[i]-1]+p]) p++;
    		height[rk[i]]=p;
    	}
    }
    
    ll tmp[maxn];
    int pre[maxn],nxt[maxn];
    
    int main() {
    	read(n);for(int i=1;i<=n;i++) read(w[i]),r[i]=w[i];
    	sort(r+1,r+n+1);int M=unique(r+1,r+n+1)-r-1;
    	for(int i=1;i<=n;i++) w[i]=lower_bound(r+1,r+M+1,w[i])-r;
    	reverse(w+1,w+n+1);
    	build();
    
    	for(int i=1;i<n;i++) nxt[i]=i+1;
    	for(int i=2;i<=n;i++) pre[i]=i-1;
    
    	for(int i=1;i<=n;i++) {
    		int x=rk[i];
    		int mn=max(height[x],height[nxt[x]]);
    		tmp[i]=n-i+1-mn;
    		height[nxt[x]]=min(height[nxt[x]],height[x]);
    		height[x]=0;
    		pre[nxt[x]]=pre[x];
    		if(x) nxt[pre[x]]=nxt[x];
    	}
    	reverse(tmp+1,tmp+n+1);
    	for(int i=1;i<=n;i++) tmp[i]+=tmp[i-1],write(tmp[i]);
    	return 0;
    }
    
  • 相关阅读:
    zz--Add-Migration与EF及Mysql的使用。。
    最后学期
    E. Tree Queries 题解(思维+dfs序)
    D. 0-1 MST 题解(补图的联通块)
    F. Equalizing Two Strings 题解(思维)
    CSUST 白银御行想展示 题解(思维)
    E2. Rubik's Cube Coloring (hard version) 题解(dp+思维)
    D. Hemose in ICPC ? 题解(二分+dfs序+交互)
    C. Bakry and Partitioning 题解(思维+两次dfs)
    E. Bored Bakry 题解(二进制+思维)
  • 原文地址:https://www.cnblogs.com/hbyer/p/10269046.html
Copyright © 2011-2022 走看看