加密

加密

【问题描述】

  有一种不讲道理的加密方法是: 在字符串的任意位置随机插入字符。 相应的,不讲道理的解密方法就是从字符串中恰好删去随机插入的那些字符。给定原文s和加密后的字符串t,求t有多少子串可以通过解密得到原文s。

【输入格式】

  输入第一行包含一个字符串t,第二行包含一个字符串s。

【输出格式】

  输出一行,包含一个整数,代表可以通过解密得到原文的t的子串的数量。

【样例输入】

  abcabcabc

  cba

【样例输出】

  9

【样例解释】

  用[l,r]表示子串开头结尾的下标(从 0 开始编号) ,这 9 种方案是:[0,6],[0,7],[0,8],[1,6],[1,7],[1,8],[2,6],[2,7],[2,8]

【数据规模和约定】

  对于30%的数据,|t| ≤1000。

  对于100%的数据,1 ≤ |t| ≤ 300,000,1 ≤ |s| ≤ 200。

【题目分析】

  给出字符串t,从t的子串中按顺序找出s中的每一个字符(不一定连续)。
  举个例子来说
  t:qqacbbaccbcsd
  s:ab
  发现s在t中出现了不止一次啊这尼玛怎么搞会有重复啊。
  淡定。
  定义last为上一次找到的s串中第一个元素出现的位置,初始值为0
  扫描t串找到s的第一个元素在中出现的位置时,记录为i,从这个位置开始继续往后扫,直到把s串中的元素恰好全都找到时停止,位置记录为j,那也就是说从i到j这段的字符都必须有然后两边依次加字符,那利用[i,j]这段字符串的方案数就为(i)*(len1-j+1)这是第一次扫描到s第一个元素时,如果不是第一次的话,我们就不能直接用i乘了,因为那会和前面已经计入答案的方案重复,这玩意手推一下就好。所以 方案数应该是(i-last)*(len1-j+1),last为上一次s的第一个元素出现的位置,这也就解释了为什么初始为0。

  再看一种情况,上面的例子中 出现了acbb,这种情况下只要计算第一个b就好了,因为计算第一个的时候第二个的所有情况都包含在内,而计算第二个却没办法把第一个包含(额...语文水平有限,太罗嗦),这就是为嘛扫一遍就能计算出正确答案。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int len1,len2;
long long ans;
char t[300010],s[205];

int main()
{
    freopen("encrypt.in","r",stdin);
    freopen("encrypt.out","w",stdout);
    scanf("%s",t+1);
    scanf("%s",s+1);
    len1=strlen(t+1);
    len2=strlen(s+1);
    int last=0;
    for(int i=1;i<=len1;i++)
    {
        int cnt=1,j;
        if(t[i]==s[1])
        {
            for(j=i;j<=len1;j++)
            {
                if(cnt==len2+1)
                    break;
                if(t[j]==s[cnt])
                    cnt++;
            }
            
            if(cnt==len2+1)
                j--,
                ans+=(i-last)*(len1-j+1),
                last=i;
        }
    }
    cout<<ans;
    fclose(stdin);fclose(stdout);
    return 0;
}
原文地址:https://www.cnblogs.com/xiaoningmeng/p/6057089.html