题目
给一个只由01构成的,长度不超过50的串,
问存在多少种划分方式,使得划分方式中对应的每个连续序列的和所构成的新序列是回文序列,
两个新序列不同当且仅当划分位置不完全相同。
比如1001,若不划分为2;若10|01,则新序列为1,1
思路来源
钱神代码&&归神代码
题解
枚举外面两段,统计中间一段的方案个数,
记忆化搜索中间一段的方案个数,
循环的区间dp应该也能写,然而凡神的代码看不懂,就这样叭……
dfs(i+1,j-1)相当于在i和i+1之间插挡板,在j和j-1之间插挡板
注意到,如果i+2==j时,dfs(i+1,j-1)会导致新的i和j相等,
而如果i+1==j时,dfs(i+1,j-1)会导致i和j错位,
但其实是在i和j之间插了一个挡板,也是有一个合法答案的
注意到插挡板的这个j>i之后,剩下的就没啥了吧
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
char s[105];
int T,len;
ll dp[105][105];
ll dfs(ll l,ll r)
{
if(l>=r)return 1;
if(~dp[l][r])return dp[l][r];
dp[l][r]=1;
int lsum=0,rsum=0;
for(int i=l;i<r;i++)
{
rsum=0;
lsum+=s[i]-'0';
for(int j=r;j>i;j--)
{
rsum+=s[j]-'0';
if(lsum==rsum)dp[l][r]+=dfs(i+1,j-1);
if(dp[l][r]>=mod)dp[l][r]%=mod;
}
}
return dp[l][r]%mod;
}
int main()
{
scanf("%d",&T);
while(T--)
{
memset(dp,-1,sizeof dp);
scanf("%s",s+1);
len=strlen(s+1);
printf("%I64d\n",dfs(1,len));
}
return 0;
}