zoukankan      html  css  js  c++  java
  • [SDOI2016]生成魔咒 后缀自动机

    题面:洛谷

    题解:

      题意:给定串,对于每个前缀求有多少本质不同的子串。

      我们对这个串建后缀自动机,每加入一个字符就更新一次答案,更新一次输出一次。

      对于后缀自动机上的每个状态,因为以[MINS, MAXS]中的每个值作为长度都可以表示一个不同的子串,所以这个状态的贡献就是这个区间的长度。

      因此建的时候更新ans即可

      

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define LL long long
     4 #define R register int
     5 #define AC 201000
     6 
     7 LL ans;
     8 struct sam_atm{
     9     int last, cnt;
    10     map<int, int> ch[AC];//因为任意一个字符都可能是一个超大的数字,所以要用map
    11     int fa[AC], l[AC];
    12     
    13     inline void add(int c)
    14     {
    15         int p = last, np = ++ cnt;
    16         last = np, l[np] = l[p] + 1;
    17         for( ; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;//对于没有这条边的点,加上这条边
    18         if(!p) fa[np] = 1, ans += l[np] - l[1];//加上贡献
    19         else
    20         {
    21             int q = ch[p][c];//找到第一个有c这条边的节点的这条边对应的状态
    22             if(l[p] + 1 == l[q]) fa[np] = q, ans += l[np] - l[q];//如果不会产生影响,就直接接上去
    23             else
    24             {
    25                 int nq = ++ cnt;//再新建一个节点
    26                 l[nq] = l[p] + 1;//长度+1
    27                 ch[nq] = ch[q], ans -= l[q] - l[fa[q]];//这是map自带的功能???
    28                 //memcpy(ch[nq], ch[q], sizeof(ch[q]));//把对应状态的所有边都赋值到新点上
    29                 fa[nq] = fa[q], ans += l[nq] - l[fa[nq]];//把新点连上去,把q拉下来,因为q的位置被改变了,所以要重新统计它的贡献,即删去原来的,加上新的
    30                 fa[q] = fa[np] = nq, ans += l[q] + l[np] - (l[nq] << 1);//把这2个点都放在下面
    31                 for( ; ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
    32             }//因为这里没有涉及fa的改变,所以[Min(s), Max(s)]也没有发生改变,无需修改ans
    33         }
    34     }
    35     
    36 }sam;
    37 
    38 inline int read()
    39 {
    40     int x = 0;char c = getchar();
    41     while(c > '9' || c < '0') c = getchar();
    42     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    43     return x;
    44 }
    45 
    46 void work()
    47 {
    48     int n = read();
    49     sam.last = sam.cnt = 1;//记得初始化!
    50     for(R i = 1; i <= n; i ++)
    51     {
    52         sam.add(read());
    53         printf("%lld
    ", ans);
    54     }
    55 }
    56 
    57 int main()
    58 {
    59 //    freopen("in.in", "r", stdin);
    60     work();
    61 //    fclose(stdin);
    62     return 0;
    63 }
    View Code

      

  • 相关阅读:
    mvc 数据验证金钱格式decimal格式验证
    VMware与CentOS的安装与Linux简单指令
    rbac组件引用
    Django--CRM--菜单展示, 删除合并, 权限展示
    Django--CRM--菜单排序等
    Django--CRM--一级, 二级 菜单表
    Django--权限信息操作
    Django--CRM--modelformset的用法
    Django--CRM--QueryDict, 模糊搜索, 加行级锁
    Django--CRM-客户列表展示, 分页
  • 原文地址:https://www.cnblogs.com/ww3113306/p/10067575.html
Copyright © 2011-2022 走看看