• [JZOJ3484]密码


    题目大意:
      给你一个很长的字符串a(|a|<=300000),一个比较短的字符串b(|b|<=200),请你搞一些破坏。
      你可以从a的两边去掉一些字符使得b仍是a的一个字串,问有多少种方案?

    思路:
      首先预处理一下串a,用f[i][j]记录对于第i个位置的字符,左边最靠近i的字符j在哪里。
      然后枚举每一个字符作为最后一个字符,往前跳,如果把整个b串跳完了,就说明减掉这两边的都没关系,计入方案。
      设a的范围为(1,n),b的范围为(i,j)那么答案增加i*(n-j+1)。
      然而这样会重复算很多,不去重直接爆零了。
      考虑如何去重。
      记录一下上次找到的序列最右边的端点在哪里,记为last,答案增加i*(last-j)。

     1 #include<cstdio>
     2 #include<cstring>
     3 typedef long long int64;
     4 const int N=300002,M=202;
     5 char s[N],t[M];
     6 int f[N][26];
     7 inline int idx(const char &ch) {
     8     return ch-'a';
     9 }
    10 int main() {
    11     scanf("%s%s",s+1,t+1);
    12     int n=strlen(s+1),m=strlen(t+1);
    13     for(register int i=1;i<n;i++) {
    14         memcpy(f[i+1],f[i],sizeof *f);
    15         f[i+1][idx(s[i])]=i;
    16     }
    17     int64 ans=0;
    18     int last=n+1;
    19     for(register int i=n;i;i--) {
    20         if(s[i]!=t[m]) continue;
    21         for(register int j=m,k=i,l;j&&k;k=f[l=k][idx(t[--j])]) {
    22             if(j==1) {
    23                 ans+=k*(last-i);
    24                 last=i;
    25             }
    26         }
    27     }
    28     printf("%lld
    ",ans);
    29     return 0;
    30 }
  • 相关阅读:
    UVa 820 因特网带宽(最大流)
    UVa 1001 奶酪里的老鼠(Dijkstra或Floyd)
    UVa 821 网页跳跃(Floyd)
    UVa 11624 大火蔓延的迷宫
    UVa 10881 蚂蚁
    UVa 11300 分金币
    UVa 11729 突击战
    《额尔古纳河右岸》读书笔记
    HDU 1083 Courses(二分图匹配模板)
    UVa 10618 跳舞机
  • 原文地址:https://www.cnblogs.com/skylee03/p/7765472.html
Copyright © 2020-2023  润新知