加密

!!!試題來自清北!!!

【问题描述】
有一种不讲道理的加密方法是: 在字符串的任意位置随机插入字符。 相应的,
不讲道理的解密方法就是从字符串中恰好删去随机插入的那些字符。
给定原文s和加密后的字符串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%的数据,|l| 1000。
对于100%的数据,1 ≤ |l| ≤ 300,000,1 ≤ s ≤ 200。

有一種不講道理的算法,方案數+=(l+1)*(r+1)。

有一種更不講道理的去重方法,方案數-=(這次及前次中較小的l+1)*(這次及前次中較大的r+1)。

這裡的[l,r]指最窄的滿足條件的區間(即該區間對應的t的子串中依次出現組成s的字符,且t[l]==s[0],t[r]==s[ls-1]。)(不要理解成只有一組區間)。

代碼實現:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 using namespace std;
 5 long long lt,ls,jl[2],ans;//注意开long long。
 6 char t[3000000],s[300];
 7 bool p;
 8 void sf(long long x,long long y,long long z){
 9 if(y==ls){
10 ans+=(z+1)*(lt-x+1);//無理的公式應用。
11 if(jl[1]-jl[0]>=ls-1) ans-=(min(jl[0],z)+1)*(lt-max(jl[1],x-1));//無理的公式應用。
12 jl[0]=z;jl[1]=x-1;//只需要存下上一組就夠了。
13 return;
14 }
15 for(int i=x;i<lt;i++){
16 if(t[i]==s[y]){
17 if(y) {sf(i+1,y+1,z);break;}//break確保找的是最窄的合法區間。
18 else sf(i+1,y+1,i);//i存左端點。
19 }
20 }
21 }
22 int main(){
23 freopen("encrypt.in","r",stdin);
24 freopen("encrypt.out","w",stdout);
25 cin>>t>>s;
26 lt=strlen(t);ls=strlen(s);
27 sf(0,0,0);
28 cout<<ans<<endl;
29 return 0;
30 }
View Code

有時候不要嘗試打開一些很大的輸入文件,數據流失會坑死你,我就調了一個多小時的AC代碼(當時沒過是數據範圍開小了,考試注意臨終檢查)。。。

原文地址:https://www.cnblogs.com/J-william/p/6056787.html