• Bzoj4516 [Sdoi2016]生成魔咒


    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 947  Solved: 529

    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

    HINT

     

    Source

    字符串 后缀自动机

    刷刷水题233

    每添加一个字符,ans+=L[np]-L[fa[np]]

    想一想,为什么?(逃)

    后缀自动机上一个结点存的可能是多个后缀(也就是多个串),根据SAM的基本概念可以知道,这些串的长度互不相同且连续变化,记其中最长的长度为max,最短的长度为min,那么就有max-min+1个不同的串。

    又根据SAM的性质可以知道min[x]=max[fa[x]]+1,所以这个结点有$ max[x]-(max[fa[x]]+1) +1 $个不同的串。

    后缀自动机上不同的结点存的串本质不同,所以可以如上累加。

     1 /*by SilverN*/
     2 #include<algorithm>
     3 #include<iostream>
     4 #include<cstring>
     5 #include<cstdio>
     6 #include<cmath>
     7 #include<vector>
     8 #include<map>
     9 #define LL long long
    10 using namespace std;
    11 const int mxn=201010;
    12 int read(){
    13     int x=0,f=1;char ch=getchar();
    14     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    15     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    16     return x*f;
    17 }
    18 void write(LL x){
    19     if(x<0)putchar('-'),x=-x;
    20     if(x>9)write(x/10);
    21     putchar(x%10+'0');
    22     return;
    23 }
    24 struct SAM{
    25     map<int,int>t[mxn];
    26     int fa[mxn],l[mxn];
    27     int S,last,cnt;
    28     LL ans;
    29     void init(){
    30         S=last=cnt=1;ans=0;
    31         return;
    32     }
    33     void add(int c){
    34         int p=last,np=++cnt;last=np;
    35         l[np]=l[p]+1;
    36         for(;p && !t[p][c];p=fa[p])t[p][c]=np;
    37         if(!p){fa[np]=S;}
    38         else{
    39             int q=t[p][c];
    40             if(l[q]==l[p]+1){
    41                 fa[np]=q;
    42             }
    43             else{
    44                 int nq=++cnt;
    45                 l[nq]=l[p]+1;
    46                 t[nq]=t[q];
    47                 fa[nq]=fa[q];
    48                 fa[q]=fa[np]=nq;
    49                 for(;p && t[p][c]==q;p=fa[p])t[p][c]=nq;
    50             }
    51         }
    52         ans+=l[np]-l[fa[np]];
    53         return;
    54     }
    55 }sa;
    56 int n,x;
    57 int main(){
    58     int i,j;
    59     n=read();
    60     sa.init();
    61     for(i=1;i<=n;i++){
    62         x=read();
    63         sa.add(x);
    64         write(sa.ans);puts("");
    65     }
    66     return 0;
    67 }
  • 相关阅读:
    [zz]std::vector,std::deque,std::list的区别的使用
    [zz]有关写c++代码的习惯
    [zz]Ubuntu linux 基本操作 双网卡双IP配置
    [zz]ZooKeeper 典型的应用场景
    [zz]Ubuntu配置双网卡
    java配置文件问题
    Struts2知识积累(2)_核心概念:拦截器
    【双旦献礼】PortalBasic Java Web 应用开发框架 v3.0.1 正式发布(源码、示例及文档)
    hibernate入门
    为Eclipse定制你自己的注释模板变量
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/6653706.html
Copyright © 2020-2023  润新知