题目描述
农夫约翰最近想发一些秘密的信息,但是他不想让奶牛们知道。这些信息是‘A’到’Z’的字符组成的,长度至少是2。
为了对这些信息进行加密,农夫约翰对这些信息进行了一系列的操作,每次操作,约翰把字符串S去掉从第一个开始连续的若干个字符或者从最后一个字符开始连续若干个字符(至少去掉一个字符,也不能全部去掉),然后把剩余的字符串添加到原来S串的左边或者右边。例如,对于字符串ABC,一次操作可以有8种结果:
AABC
ABABC
BCABC
CABC
ABCA
ABCAB
ABCBC
ABCC
现在给定最后加密好的字符串,约翰想要知道这个字符串可能由多少种方法加密而来,注意,AAA可以由AA通过四种加密操作得来,虽然产生的AAA是一样的,但是加密的过程是不一样的我们就认为是不同的方法。
输入
一个字符串。
输出
输出这个加密的字符串可以由多少种方法加密而来。【答案要mod 2014】
样例输入
ABABA
样例输出
8
数据范围限制
字符串的长度不超过100。
提示
【样例说明】
我们有8种方法可以得到ABABA:
- Start with ABA -> AB+ABA
- Start with ABA -> ABA+BA
- Start with AB -> AB+A -> AB+ABA
- Start with AB -> AB+A -> ABA+BA
- Start with BA -> A+BA -> AB+ABA
- Start with BA -> A+BA -> ABA+BA
- Start with ABAB -> ABAB+A
- Start with BABA -> A+BABA、
分析
题目大意:
求一个字符串可以由多少种变化而得到,变化为:从左边(或者从右边)截取若干字符串(能删一个,不能全删),将其放在原串的左边或者右边。
这道题用是一种很奇怪的DFS。。
将一个字符串分为 a,b,…,c,d
f=a+b+…
e=…+c+d
一个for语句,我们可以得知我们截取的字符串,会在“原串”中有对应的字符串,如果存在,那么它必然在左边或者右边,不可能在左边,所以我们可以在对e或f进行继续处理。
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
using namespace std;
string str;
map<string,int>a;
int dfs(string s)
{
if(a[s]) return a[s];//记忆化
int ans=0,l;
string ff,b,c,d,e,f;
l=s.size();
for(int i=0;(i+1)*2<l;i++)
{
ff=s.substr(0,i+1);
b=s.substr(i+1,i+1);
c=s.substr(l-i-1,i+1);
d=s.substr(l-i-i-2,i+1);
e=s.substr(i+1,l-i-1);
f=s.substr(0,l-i-1);
if(ff==b) ans+=dfs(e);
if(ff==c) ans+=dfs(e);
if(c==ff) ans+=dfs(f);
if(c==d) ans+=dfs(f);
}
if(l>=2) ans++;
ans%=2014;
a[s]=ans;
return ans;
}
int main()
{
freopen("scode.in","r",stdin);
freopen("scode.out","w",stdout);
cin>>str;
cout<<dfs(str)-1;
fclose(stdin);
fclose(stdout);
return 0;
}