加密
!!!試題來自清北!!!
【问题描述】
有一种不讲道理的加密方法是: 在字符串的任意位置随机插入字符。 相应的,
不讲道理的解密方法就是从字符串中恰好删去随机插入的那些字符。
给定原文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]。)(不要理解成只有一組區間)。
代碼實現:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
有時候不要嘗試打開一些很大的輸入文件,數據流失會坑死你,我就調了一個多小時的AC代碼(當時沒過是數據範圍開小了,考試注意臨終檢查)。。。