区间DP--CH 5302

传送门
f [ l ] [ r ] f[l][r] f[l][r] s [ l ⋅ ⋅ ⋅ r ] s[l···r] s[lr]的序列能构成的树的方案数,就可以考虑转移,首先 s [ l ] s[l] s[l]必须等于 s [ r ] s[r] s[r],然后我们可以让 s [ l ] s[l] s[l]作为当前的根,用乘法原理枚举 k k k转移,那么 s [ k ] s[k] s[k]一定要等于 s [ r ] s[r] s[r]

如果 l + 1 ≤ k ≤ r − 2 ​ l+1\le k \le r-2​ l+1kr2,则
f [ l ] [ r ] + = f [ l + 1 ] [ k − 1 ] × f [ k ] [ r ] ​ f[l][r]+=f[l+1][k-1]\times f[k][r]​ f[l][r]+=f[l+1][k1]×f[k][r]

如果 k = r − 1 k=r-1 k=r1,则
f [ l ] [ r ] + = f [ l + 1 ] [ r − 2 ] × f [ r − 1 ] [ r ] = f [ l + 1 ] [ r − 2 ] × 0 = 0 f[l][r]+=f[l+1][r-2]\times f[r-1][r]=f[l+1][r-2]\times 0=0 f[l][r]+=f[l+1][r2]×f[r1][r]=f[l+1][r2]×0=0

如果 k = r k=r k=r,则
f [ l ] [ r ] + = f [ l + 1 ] [ r − 1 ] × f [ r ] [ r ] = f [ l + 1 ] [ r − 1 ] × 1 = f [ l + 1 ] [ r − 1 ] . f[l][r]+=f[l+1][r-1]\times f[r][r]=f[l+1][r-1]\times 1=f[l+1][r-1]. f[l][r]+=f[l+1][r1]×f[r][r]=f[l+1][r1]×1=f[l+1][r1].

所以式子可以统一写成
f [ l ] [ r ] + = ∑ k = l + 2 r f [ l + 1 ] [ k − 1 ] × f [ k ] [ r ]   ( s [ k ] = = s [ r ] ) f[l][r]+=\sum_{k=l+2}^rf[l+1][k-1]\times f[k][r]\ (s[k]==s[r]) f[l][r]+=k=l+2rf[l+1][k1]×f[k][r] (s[k]==s[r])

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 305
using namespace std;
int f[maxn][maxn],n;
const int mod=1e9;
char s[maxn];

int main(){
	scanf("%s",s+1); n=strlen(s+1);
	for(int i=1;i<=n;i++) f[i][i]=1;
	for(int i=2;i<=n;i++)
		for(int l=1;l<=n-i+1;l++){
			int r=l+i-1;
			if(s[l]!=s[r]) continue;
			for(int k=l+2;k<=r;k++)
				if(s[k]==s[r])
				(f[l][r]+=1LL*f[l+1][k-1]*f[k][r]%mod)%=mod;
		}
	printf("%d\n",f[1][n]);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值