金字塔

金字塔
  • 题目

    金字塔

  • 分析

    f [ l ] [ r ] f[l][r] f[l][r] 表示 子串 s [ l ∼ r ] s[l \sim r] s[lr] 对应着多少不同方案数。如果枚举子串 s [ l ∼ r ] s[l \sim r] s[lr] 划分点数量和所有划分点的位置,复杂度太高。

    又可想到把子串分成两个部分,每部分可由若干颗子树组成,不过这样可能会产生重复计数。

    所以可以只考虑子串 s [ l ∼ r ] s[l \sim r] s[lr] 的第一颗子树是由哪一段构成的。枚举划分点 k k k ,令子串 s [ l + 1 ∼ k − 1 ] s[l + 1 \sim k-1] s[l+1k1] 构成

    [ l , r ] [l,r] [l,r] 的第一颗子树, s [ k , r ] s[k,r] s[k,r] 构成 [ l , r ] [l,r] [l,r] 的剩余部分。

    当这棵树只有一个子树时:

    F [ l , r ] = F [ l + 1 , r − 1 ] F[l,r] = F[l + 1,r - 1] F[l,r]=F[l+1,r1]
    F [ l , r ] = { 0 s [ l ] ̸ = s [ r ] F [ l + 1 , r − 1 ] + ∑ l + 2 ≤ k ≤ r − 2 F [ l + 1 , k − 1 ] × F [ k , r ] s [ l ] = = s [ r ] F[l,r]=\left\{ \begin{aligned} 0 \qquad s[l] \not= s[r]\\ F[l + 1,r - 1]+\sum_{l+2\leq k \leq r-2} F[l+1,k-1] \times F[k,r] \qquad s[l] == s[r]\\ \end{aligned} \right. F[l,r]=0s[l]̸=s[r]F[l+1,r1]+l+2kr2F[l+1,k1]×F[k,r]s[l]==s[r]
    初值: ∀ l ∈ [ 1 , N ] \forall l \in [1,N] l[1,N] , f [ l , l ] = 1 f[l,l] = 1 f[l,l]=1 其余为 0 0 0 .

    目标: f [ 1 , N ] f[1,N] f[1,N]

    k = r − 1 k = r - 1 k=r1 F [ l , r ] = 0 F[l,r] = 0 F[l,r]=0

    k = r k = r k=r F [ l , r ] = F [ l + 1 , k − 1 ] F[l,r] = F[l+1,k-1] F[l,r]=F[l+1,k1]

    所以可以转换为:
    F [ l , r ] = ∑ l + 2 ≤ k ≤ r F [ l + 1 , k − 1 ] × F [ k , r ] F[l,r] = \sum_{l+2\leq k \leq r} F[l+1,k-1] \times F[k,r] F[l,r]=l+2krF[l+1,k1]×F[k,r]

  • 代码

    int f[310][310];
    char s[100000];
    int solve(int l, int r)
    {
    	if (l > r) return 0;
    	if (l == r) return 1;
    	if (f[l][r] != -1) return f[l][r];
    	if(s[l] != s[r]) return 0;
    	f[l][r] = 0;
    	for (int k = l + 2; k <= r; k++)
    		f[l][r] = (f[l][r] + (ll)solve(l + 1, k - 1) * solve(k, r)) % mod;
    	return f[l][r];
    }
    int main ()
    {
    	//freopen("input.in", "r", stdin);
    	//freopen("test.out", "w", stdout);
    	scanf("%s",s+1);
        memset(f,-1,sizeof(f));
        cout << solve(1,strlen(s+1)) << endl;
     	return 0 ;
    }
    
  • 题型

    区间 D P DP DP

大佬普通写法

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值