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

  • 相关阅读:
    Call KernelIoControl in user space in WINCE6.0
    HOW TO:手工删除OCS在AD中的池和其他属性
    关于新版Windows Server 2003 Administration Tools Pack
    关于SQL2008更新一则
    微软发布3款SQL INJECTION攻击检测工具
    HyperV RTM!
    OCS 2007 聊天记录查看工具 OCSMessage
    CoreConfigurator 图形化的 Server Core 配置管理工具
    OC 2007 ADM 管理模板和Live Meeting 2007 ADM 管理模板发布
    Office Communications Server 2007 R2 即将发布
  • 原文地址:https://www.cnblogs.com/antiquality/p/10511165.html
Copyright © 2011-2022 走看看