• 【SAM】loj#6401. 字符串


    网上有篇题解写的是线段树合并维护求值?

    题目描述

      有一个只包含小写字母,长度为 $n$ 的字符串 $S$ 。有一些字母是好的,剩下的是坏的。

      定义一个子串 $S_{lldots r}$是好的,当且仅当这个子串包含不超过 $k$ 个坏的字母。

      求有多少个不同的满足以下要求的字符串 $T$ :

    • $T$ 作为 $S$ 的子串出现过。
    • 存在一个 $T$ 出现的位置 $[l,r]$ ,满足 $S_{lldots r}$​ 是好的。

    输入格式

      第一行有一个字符串 $S$ 。

      第二行有一个字符串 $B$ 。若 $B_i=‘1’$ 则表示 $S_i$​ 是好的,否则表示 $S_i$ 是坏的。

      第三行有一个整数 $k$ 。

    输出格式

      一个整数:答案。

    数据范围与提示

      子任务 $1$($10$ 分):$nleq 10$。

      子任务 $2$($10$ 分):$nleq 100$。

      子任务 $3$($10$ 分):$nleq 1000$。

      子任务 $4$($10$ 分):$nleq 100000,k=n$。

      子任务 $5$($10$ 分):$nleq 100000,k=0$。

      子任务 $6$($20$ 分):$nleq 100000$,若$S_i=S_j$​,则$B_i=B_j$​。

      子任务 $7$($30$ 分):$nleq 100000$。

      对于 $100\%$ 的数据:$1leq nleq {10}^5,0leq kleq {10}^5$, $S$ 只包含小写字母。

      题目来源:全是水题的GDOI模拟赛 by yww


    题目分析

    定位:比较模板的SAM题(然而我一个月前并不会SAM)

    题意即求满足一定条件的若干个字符串里本质不同的子串个数。当然这里的“一定条件”比较特殊,是连续的一段子串。(如果这里的“一定条件”字符串是若干个互不相干的串,似乎就需要“广义后缀自动机”来处理了)

    既然对于每一个新增的节点,其合法的子串都有一个左边界,那么在SAM里处理的时候,就可以对每一节点加一个权值$mx[u]$表示该节点的最长合法扩展长度。这个权值的作用就在于建完自动机后的$calc()$,原先数本质不同的子串个数是这样的: ans += len[p]-len[fa[p]]; 现在就是 ans += std::max(std::min(mx[p], len[p])-len[fa[p]], 0); 。记得注意一下extend里对mx的转移。

     1 #include<bits/stdc++.h>
     2 const int maxn = 200035;
     3 
     4 int n,lim,sum[maxn],size[maxn],cnt[maxn],pos[maxn];
     5 long long ans;
     6 struct SAM
     7 {
     8     int ch[maxn][27],fa[maxn],len[maxn],mx[maxn],lst,tot;
     9     void init()
    10     {
    11         lst = tot = 1;
    12     }
    13     void extend(int c, int v)
    14     {
    15         int p = lst, np = ++tot;
    16         lst = np, len[np] = len[p]+1, mx[np] = v;        //len[p+1]    Here  居然打成标红的这个
    17         for (; p&&!ch[p][c]; p=fa[p]) ch[p][c] = np;
    18         if (!p) fa[np] = 1;
    19         else{
    20             int q = ch[p][c];
    21             if (len[p]+1==len[q]) fa[np] = q;
    22             else{
    23                 int nq = ++tot;
    24                 len[nq] = len[p]+1, mx[nq] = mx[q];
    25                 memcpy(ch[nq], ch[q], sizeof ch[q]);
    26                 fa[nq] = fa[q], fa[q] = fa[np] = nq;
    27                 for (; p&&ch[p][c]==q; p=fa[p])
    28                     ch[p][c] = nq;
    29             }
    30         }
    31     }
    32     void calc()
    33     {
    34         for (int i=1; i<=tot; i++) ++cnt[len[i]];
    35         for (int i=1; i<=tot; i++) cnt[i] += cnt[i-1];
    36         for (int i=1; i<=tot; i++) pos[cnt[len[i]]] = i, --cnt[len[i]];
    37         for (int i=tot; i; i--)
    38         {
    39             int p = pos[i];
    40             mx[fa[p]] = std::max(mx[fa[p]], mx[p]); 
    41             ans += std::max(std::min(mx[p], len[p])-len[fa[p]], 0);
    42         }
    43     }
    44 }f;
    45 char s[maxn],t[maxn];
    46 
    47 int main()
    48 {
    49      scanf("%s%s%d",s+1,t+1,&lim);
    50      n = strlen(s+1);
    51      f.init();
    52      for (int i=1, j=0; i<=n; i++)
    53      {
    54         sum[i] = (t[i]=='0')+sum[i-1];
    55         while (sum[i]-sum[j] > lim) ++j;
    56         f.extend(s[i]-'a'+1, i-j);
    57      }
    58      f.calc();
    59      printf("%lld
    ",ans);
    60      return 0;
    61 }

    END

  • 相关阅读:
    C++ 内置函数 判断字母、数字及大小写转换
    C++11 随机数 random
    rpc
    C++11 智能指针
    xargs 命令使用
    记录优秀的文章
    腾讯 测试开发
    struts2文件上传、下载、防止重复提交
    注解
    @RestController注解
  • 原文地址:https://www.cnblogs.com/antiquality/p/10511165.html
Copyright © 2020-2023  润新知