题目描述
Farmer John有一段长度至少为2的仅由大写字母组成的代码,现在他要对这段代码进行一次或一次以上的骚操作。对于一段代码S,Farmer John可以有如下的骚操作:把S的开头一个字母或结尾一个字母去掉,接在S的开头或结尾作为新的代码。例如ABCD经过一次骚操作可以变成的代码有:BCDABCD、ABCDBCD、ABCABCD、ABCDABC。
再举一个例子,ABA经过一次骚操作可以变成的代码有:BAABA、ABABA、ABABA、ABAAB。
尽管ABABA和ABABA看起来是相同的,但由于它是由不同的方式拼接而来,我们认为这两种是不同的方案。
现在给出Farmer John进行了一次或一次以上骚操作的代码,你需要计算可能的操作出这段代码的方案数。
输入
输入只有一行,一个仅由大写字母构成的字符串S,表示操作之后的代码。
输出
输出只有一行,表示可能的方案数。
样例输入
ABABA
样例输出
6
提示
(1)ABA→AB+ABA。
(2)ABA→ABA+BA。
(3)AB→AB+A→AB+ABA。
(4)AB→AB+A→ABA+BA。
(5)BA→A+BA→AB+ABA。
(6)BA→A+BA→ABA+BA。
对于50%的数据,1≤∣S∣≤300。
对于100%的数据,1≤∣S∣≤105。
思路
暴力求解,因为获取字符串的组合方式必定为 2*n-1,所以当获取的字符串长度为偶数时,此字符串必定没有原串,当获取的字符串长度为奇数时,模拟字符串的构建,推得构建串所需的原字符串截取部位的位置,即可递归实现
代码实现
参考自大佬的代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
char s[N];
ll dfs(int l,int r)
{
int len=r-l+1;
int mid=(l+r)>>1;
if(len%2==0) return 1;
bool flag=true;
ll ans=1,ll=0,rr=0;
for(int i=l,j=mid+1;i<mid && j<=r;i++,j++)
{
if(s[i]!=s[j])
{
flag=false;
break;
}
}
if(flag) ll++,rr++;
flag=true;
for(int i=l+1,j=mid+1;i<=mid && j<=r;i++,j++)
{
if(s[i]!=s[j])
{
flag=false;
break;
}
}
if(flag) ll++;
flag=true;
for(int i=l,j=mid;i<mid && j<r;i++,j++)
{
if(s[i]!=s[j])
{
flag=false;
break;
}
}
if(flag) rr++;
flag=true;
if(ll) ans+=ll*dfs(l,mid);
if(rr) ans+=rr*dfs(mid,r);
return ans;
}
int main()
{
scanf("%s",s);
int len=strlen(s);
printf("%lld\n",dfs(0,len-1)-1);
}