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


    1 2 3 3 3 1 2

    Sample Output





    12 
    17 
    22

    Hint

    数据约束: 
    对于 10% 的数据,1≤n≤10。 
    对于 30% 的数据,1≤n≤100。 
    对于 60% 的数据,1≤n≤1000。 
    对于 100% 的数据,1≤n≤100000。 
    用来表示魔咒字符的数字 x 满足 1≤x≤109。

     
    题解:
    SAM的裸题,但是打得后缀数组,显然是可以的,要求的是每个前缀的子串数,显然反转一下就变成了后缀的子串数
    imagine一下求平时子串个数的过程,L-lcp+1 lcp为i和i+1的high[i] 显然这个题我们就可以类似的处理
    加一个字符反转后就相当于加一个后缀,我们考虑他的贡献,显然之和他rk的前驱后继有关,于是我们减去原来的再加上现在的即可成为答案,前驱后继SET维护即可,或者玩玩SPLAY Treap也挺好
      1 #include <algorithm>
      2 #include <iostream>
      3 #include <cstdlib>
      4 #include <cstring>
      5 #include <cstdio>
      6 #include <cmath>
      7 #include <set>
      8 using namespace std;
      9 const int N=100005,INF=2e8;
     10 int n,sa[N],rk[N],high[N],c[N],x[N],b[N],bc[N],num=0,s[N],y[N],bel[N];
     11 int gi(){
     12     int str=0;char ch=getchar();
     13     while(ch>'9' || ch<'0')ch=getchar();
     14     while(ch>='0' && ch<='9')str=(str<<1)+(str<<3)+ch-48,ch=getchar();
     15     return str;
     16 }
     17 int midit(int x){
     18     int l=1,r=num,mid;
     19     while(l<=r){
     20         mid=(l+r)>>1;
     21         if(bc[mid]==x)return mid;
     22         if(x>bc[mid])l=mid+1;
     23         else r=mid-1;
     24     }
     25 }
     26 int k;
     27 bool comp(int i,int j){
     28     return y[i]==y[j] && y[i+k]==y[j+k];
     29 }
     30 void Getsa(){
     31     int m=num,t;
     32     for(int i=0;i<=m;i++)c[i]=0;
     33     for(int i=1;i<=n;i++)c[x[i]=bel[i]]++;
     34     for(int i=1;i<=m;i++)c[i]+=c[i-1];
     35     for(int i=n;i>=1;i--)sa[c[x[i]]--]=i;
     36     for(k=1;k<=n;k<<=1){
     37         t=0;
     38         for(int i=0;i<=m;i++)y[i]=0;
     39         for(int i=n-k+1;i<=n;i++)y[++t]=i;
     40         for(int i=1;i<=n;i++)if(sa[i]>k)y[++t]=sa[i]-k;
     41         for(int i=0;i<=m;i++)c[i]=0;
     42         for(int i=1;i<=n;i++)c[x[i]]++;
     43         for(int i=1;i<=m;i++)c[i]+=c[i-1];
     44         for(int i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i];
     45         swap(x,y);
     46         x[sa[1]]=t=1;
     47         for(int i=2;i<=n;i++)x[sa[i]]=comp(sa[i-1],sa[i])?t:++t;
     48         if(t==n)break;
     49         m=t;
     50     }
     51     for(int i=1;i<=n;i++)rk[sa[i]]=i;
     52 }
     53 void Gethight(){
     54     int j,h=0;
     55     for(int i=1;i<=n;i++){
     56         j=sa[rk[i]-1];
     57         if(h)h--;
     58         for(;j+h<=n && i+h<=n;h++)if(s[i+h]!=s[j+h])break;
     59         high[rk[i]-1]=h;
     60     }
     61 }
     62 long long ans[N];
     63 set<int>p;
     64 int f[N][21];
     65 void prework(){
     66     int to;
     67     for(int i=1;i<=n;i++)f[i][0]=high[i];
     68     for(int j=1;j<=20;j++)
     69         for(int i=1,tmp=n-(1<<j)+1;i<=tmp;i++){
     70             to=i+(1<<(j-1));
     71             if(f[i][j-1]<f[to][j-1])f[i][j]=f[i][j-1];
     72             else f[i][j]=f[to][j-1];
     73     }
     74 }
     75 int query(int l,int r){
     76     int k=log(r-l+1)/log(2);
     77     return min(f[l][k],f[r-(1<<k)+1][k]);
     78 }
     79 int lcp(int i,int j){
     80     return query(i,j-1);
     81 }
     82 long long cnt[N];
     83 void Getanswer(){
     84     long long sum=0;
     85     int pre,nxt,now;
     86     set<int>::iterator iter;
     87     p.insert(n+1);p.insert(0);
     88     for(int i=n;i>=1;i--){
     89         now=rk[i];
     90         iter=(--p.lower_bound(now));
     91         if(iter!=p.begin()){
     92             pre=*(iter);
     93              sum-=cnt[pre];
     94             cnt[pre]=(n-sa[pre]+1-lcp(pre,now));
     95             sum+=cnt[pre];
     96         } 
     97         nxt=*(p.upper_bound(now));
     98         cnt[now]=(n-sa[now]+1-lcp(now,nxt));
     99         sum+=cnt[now];
    100         ans[n-i+1]=sum;
    101         p.insert(now);
    102     }
    103     for(int i=1;i<=n;i++)printf("%lld
    ",ans[i]);
    104 }
    105 int main()
    106 {
    107     freopen("menci_incantation.in","r",stdin);
    108     freopen("menci_incantation.out","w",stdout);
    109     n=gi();
    110     for(int i=1;i<=n;i++)s[i]=gi();
    111     for(int i=1,t=n>>1;i<=t;i++)swap(s[i],s[n-i+1]);
    112     for(int i=1;i<=n;i++)b[i]=s[i];
    113     sort(b+1,b+n+1);for(int i=1;i<=n;i++)if(b[i]!=b[i+1])bc[++num]=b[i];
    114     for(int i=1;i<=n;i++)bel[i]=midit(s[i]);
    115     Getsa();Gethight();prework();Getanswer();
    116     return 0;
    117 }
  • 相关阅读:
    Android PopupWindow显示位置和显示大小
    线性回归与梯度下降
    nginx启动过程分析
    项目管理学习笔记之三.绩效分析
    会计总论读书笔记
    电子书阅读及工具
    mybatis-mysql小优化
    List去重
    JAVA8之lambda表达式详解,及stream中的lambda使用
    linux部署mongodb及基本操作
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7184093.html
Copyright © 2011-2022 走看看