zoukankan      html  css  js  c++  java
  • BZOJ4516: [Sdoi2016]生成魔咒

    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

    题解Here!
    据说这题可以被$SAM$秒杀,然而本蒟蒻只会$SA$。。。
    题目要求出每一个前缀本质不同的后缀的个数。
    那么我们可以把原序列倒过来,然后实际上就是对于每一个后缀求与其它后缀不重复的前缀个数,也即是后缀长度减去$height$。
    求出某一个后缀对答案的贡献之后,他不应该停留在元序列中对后续答案的求解产生影响,所以应该把它删除。
    这个可以用平衡树来完成。
    但是考虑到每一个位置只与前后有关,我们可以用链表来代替。
    还有,要离散化。。。
    附代码:
    #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
    ",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;
    }
    
  • 相关阅读:
    4、redis之使用commons-pool
    好用的eclipse properties插件
    1、redis之安装与配置
    谷歌浏览器禁止window.close的问题
    在浏览器中使用JS打开并展示PDF文件
    JAVA遍历Map的方法
    GEOS库学习之三:空间关系、DE-9IM和谓词
    GEOS库的学习之二:简单几何图形的创建
    GEOS库的学习之一:介绍和编译
    GEOS库在windows中的编译和测试(vs2012)
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9447643.html
Copyright © 2011-2022 走看看