【问题描述】
假发通过了不懈的努力,得到了将军家门锁的密码(一串小写英文字母)。但是假发被十四和猩猩他们盯上了,所以假发需要把密码传递出去。因为假发不想十四他们发现几松门前贴的小纸条就是将军家的密码,所以他加密了密码(新八:听起来有点诡异)。加密方法如下:随机地,在密码中任意位置插入随机长度的小写字符串。
不过,假发相信银桑和他那么多年小学同学,一定能猜中密码是什么的(新八:银桑什么时候成攮夷志士了!!!)。可是,写完了小纸条之后,假发觉得有点长,就想截去头和尾各一段(可以为空),让剩下的中间那一段依然包含真~密码。想着想着,假发就想知道有多少种可行方案。结果在沉迷于稿纸之际,假发被投进了狱门岛(新八:……)。于是,就由你计算了。
【输入格式】
两行非空字符串,纯小写英文字母,第一行是加密后的密码,第二行是原密码。第一行长度不超过 300000,第二行不超过 200。
【输出格式】
一行,有多少种方案。注意:不剪也是一种方案。
【输入样例】
【样例1】
abcabcabc
cba
【样例2】
abcabcaba
cba
【样例3】
abcabcabac
cba
【输出样例】
【样例1】
9
【样例2】
12
【样例3】
18
【样例解释】
【样例1解释】
用(L,R)表示一种方案,其中L和R分别表示截去头和尾的长度。这9种方案分别是 (0,0),(0,1),(0,2),(1,0),(1,1),(1,2),(2,0),(2,1),(2,2)。
【数据范围】
30%的数据满足第一行长度不超过1000。
100%的数据满足第一行长度不超过300000,方案总数不超过10^18。
首先从加密字符串中寻找密码的开头字符,存储此时开头字母下标w,更新之前出现过密码的开头字符的下标q,然后依次往后找密码的其他字符,直到找到末尾字符,此时计算方案数ans+=(w-p)*(n+1-i)。因为随着不断的寻找,有多个密码出现时肯定会出现重复计算的问题,所以记录开头字母下标可以避免重复计算。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
long long ans=0;
char ch[300005],cmd[205];
int main()
{
//freopen("password.in","r",stdin);
//freopen("password.out","w",stdout);
scanf("%s",ch);
scanf("%s",cmd);
int n=strlen(ch)-1;
int m=strlen(cmd)-1;
int s=0,t=n,p=0,w=-1;
int i=0,j=0;
while(i<=n)
{
while(i<=n&&ch[i]!=cmd[j]) i++;
if(i>n) break;
if(j==0) p=w,w=i;
if(j==m) ans+=(w-p)*(n+1-i);
i++,j++;
if(j>m) j=0,i=w+1;
}
printf("%I64d",ans);
return 0;
}