题意
给你一个偶数长度的字符串,你想要给每一个字符标记成蓝色或者红色,使得红色的字符序列等于蓝色的字符序列,一共有多少种方法可以做这件事
输入格式
输入一行包含一个字符串(S, (2≤|S|≤40))
字符串的每个字符为'o'或者'x'
输出格式
输出一个整数
样例输入&输出
样例1
oxox
2
样例2
oooxxx
0
样例3
xoxxox
4
样例4
xo
0
样例5
ooooxoox
8
样例6
ooxxoxox
8
样例7
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
137846528820
分析
本题就是要寻找长度为 (frac{|S|}{2}) 的 (S) 的子序列 (S_1) 的个数,使 (S) 的另一个子序列 (S_2) 与 (S_1) 相等,且 (S_2) 与 (S_1) 互斥,即对于任意(S_1[i],S_2[j],i≠j)。
我们能确定 (S_1) 的长度(即(frac{|S|}{2})),以及 (S_1) 中'o'和'x'的个数,于是想到爆搜穷举每一个可能的 (S_1) ,最多搜(C^{20}_{10}=184756)次。对于每一个可能的 (S_1) ,我们用(O(n^2))的dp去检验它的方案数。设 (dp[i][j]) 表示枚举到第 (i) 位,其中有 (j) 位与 (S_1) 匹配的方案数,则
[if(dp[i-1][j-1]存在且b[j]==a[i])dp[i][j]+=dp[i-1][j-1]
]
[if(dp[i-1][j]存在且b[i-j]==a[i])dp[i][j]+=dp[i-1][j]
]
初始化(dp[0][0]=1)
最终答案为(dp[n][n/2])
总时间复杂度为(O(C^{n}_{n/2}* n^2)≈295609600),卡卡常能过
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 45
using namespace std;
char s[maxn];
bool a[maxn],b[maxn];
int n,n1,n0;
long long ans,dp[maxn][maxn];
long long check(){
for(int i=0;i<=n;i++){
for(int j=0;j<=(n>>1);j++){
dp[i][j]=0;
}
}
dp[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=min(i,(n>>1));j++){
if(j&&dp[i-1][j-1]&&b[j]==a[i])dp[i][j]+=dp[i-1][j-1];
if(j<i&&dp[i-1][j]&&b[i-j]==a[i])dp[i][j]+=dp[i-1][j];
}
}
return dp[n][n>>1];
}
void dfs(int step){
if(step>(n>>1)){
ans+=check();
return;
}
if(n1){
n1--;
b[step]=1;
dfs(step+1);
n1++;
}
if(n0){
n0--;
b[step]=0;
dfs(step+1);
n0++;
}
}
int main(){
scanf("%s",s);
n=strlen(s);
for(int i=1;i<=n;i++){
a[i]=(s[i-1]=='x');
n1+=a[i],n0+=!a[i];
}
n1>>=1,n0>>=1;
dfs(1);
printf("%lld",ans);
return 0;
}