HDU5396 - Expression - 区间dp、组合数学

本文介绍了一道关于区间动态规划和组合数学的问题,通过给定数值和操作符,利用动态规划的方法求解所有可能的计算顺序下表达式结果之和,并提供了一段AC代码作为实现示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Expression

题目链接

分类:区间dp、组合数学

1.题意概述

  • 给你 n(2n100) 个数和对应 (n1) 个操作符,你每次给操作符相邻两个数加括号直到运算结束,问你最终的方案结果数的和,答案模 109+7

2.解题思路

n个操作符,计算顺序的排列组合有 n! 种,根据n的范围显然搜索的复杂度是不能接受的,我们考虑区间dp: dp[i][j] 为第i个数到第j个数的所有方案结果数的和,那么假设我们已经枚举到了区间 [i,j] 考虑第 k(ikj) 个操作符:

  • 加法的转移方程:

    dp[i][j]=Ckij(i+1)(dp[i][k][j(k+1)]!+dp[k+1][j](ki)!)

    • 阶乘表示加号左右侧的结果排列数,组合数表示区间取哪 (ki) 个数当作左侧
  • 减法的转移方程:

    dp[i][j]=Ckij(i+1)(dp[i][k][j(k+1)]!dp[k+1][j](ki)!)

  • 乘法的转移方程: dp[i][j]=Ckij(i+1)dp[i][k]dp[k+1][j]

3.AC代码

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define maxn 500010
#define lson root << 1
#define rson root << 1 | 1
#define lent (t[root].r - t[root].l + 1)
#define lenl (t[lson].r - t[lson].l + 1)
#define lenr (t[rson].r - t[rson].l + 1)
#define N 111
#define eps 1e-6
#define pi acos(-1.0)
#define e exp(1.0)
#define Close() ios::sync_with_stdio(0),cin.tie(0)
using namespace std;
const int mod = 1e9 + 7;
typedef long long ll;
typedef unsigned long long ull;
ll dp[N][N], C[N][N], A[N], a[N];
char opt[N];
void init()
{
    C[1][0] = C[1][1] = C[0][0] = C[0][1] = 1;
    A[0] = A[1] = 1;
    for(int i = 1;i <= 101;i++)
        C[i][0] = C[i][i] = 1;
    for(int i = 2;i <= 101;i++)
    {
        A[i] = A[i - 1] * i % mod;
        for(int j = 1;j < i;j++)
            C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    long _begin_time = clock();
#endif
    int n;
    init();
    while (~scanf("%d", &n))
    {
        memset(dp, 0, sizeof dp);
        for (int i = 1; i <= n; i++)
        {
            scanf("%I64d", &a[i]);
            dp[i][i] = (ll)a[i];
        }
        scanf("%s", opt + 1);
        for (int i = n; i >= 1; i--)
            for (int j = i + 1; j <= n; j++)
                for (int k = i; k < j; k++)
                    if(opt[k] == '+')
                        dp[i][j] = (dp[i][j] + (dp[i][k] * A[j - (k + 1)] % mod + dp[k + 1][j] * A[k - i] % mod) % mod * C[j - i - 1][k - i] % mod + mod) % mod;
                    else if(opt[k] == '-')
                        dp[i][j] = (dp[i][j] + (dp[i][k] * A[j - (k + 1)] - dp[k + 1][j] * A[k - i]) % mod * C[j - i - 1][k - i] % mod + mod) % mod;
                    else if(opt[k] == '*')
                        dp[i][j] = (dp[i][j] + (dp[i][k] * dp[k + 1][j] % mod) * C[j - i - 1][k - i] % mod + mod) % mod;
        printf("%I64d\n", dp[1][n]);
    }
#ifndef ONLINE_JUDGE
    long _end_time = clock();
    printf("time = %ld ms.", _end_time - _begin_time);
#endif
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值