zoukankan      html  css  js  c++  java
  • [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 }
  • 相关阅读:
    团队冲刺第五天
    每日学习
    团队冲刺第四天
    团队冲刺第三天
    每日学习
    2021.4.12
    2021.4.10
    2021.3.18
    2021.3.15
    2021.3.14
  • 原文地址:https://www.cnblogs.com/skylee03/p/7765472.html
Copyright © 2011-2022 走看看