HDU 5396 Expression 区间DP

题目描述:

Problem Description
Teacher Mai has n numbers a1,a2,⋯,anand n−1 operators(“+”, “-” or “*”)op1,op2,⋯,opn−1, which are arranged in the form a1 op1 a2 op2 a3 ⋯ an.

He wants to erase numbers one by one. In i-th round, there are n+1−i numbers remained. He can erase two adjacent numbers and the operator between them, and then put a new number (derived from this one operation) in this position. After n−1 rounds, there is the only one number remained. The result of this sequence of operations is the last number remained.

He wants to know the sum of results of all different sequences of operations. Two sequences of operations are considered different if and only if in one round he chooses different numbers.

For example, a possible sequence of operations for “1+4∗6−8∗3” is 1+4∗6−8∗3→1+4∗(−2)∗3→1+(−8)∗3→(−7)∗3→−21.

Input
There are multiple test cases.

For each test case, the first line contains one number n(2≤n≤100).

The second line contains n integers a1,a2,⋯,an(0≤ai≤109).

The third line contains a string with length n−1 consisting “+”,”-” and “*”, which represents the operator sequence.

Output
For each test case print the answer modulo 109+7.

Sample Input

3
3 2 1
-+
5
1 4 6 8 3
+*-*

Sample Output

2
999999689

Hint
Two numbers are considered different when they are in different positions.

题目分析:

输入一个n个数字,n-1个由’+’ ‘-’ ‘*’组成的表达式,其中你可以任意改变这个表达式的运算顺序(相当于在不同优先级的表达式中任意添加括号),将所有答案(不同运算顺序得到的)加起来,对1e9+7取余。
对第一个样例3-2+1只有一种运算顺序,(因为’+’和’-‘运算优先级相同),得到的答案就是2。而第二组样例得到的答案其实是一个负值,对1e9+7取模得到的答案才是这个值。
用dp[i][j]表示在第i个数到第j个数之间得出的答案之和。对于i到j之间的k个运算符进行处理。如果是’*’,将左右两端dp值相乘之后乘以一个组合数,就是在i j之间的j-i-1个运算符中选k-i到左边,其余到右边的组合数C(j-i-1,k-i)。如果是’+’或’-‘,则要将左右两边各乘上其全排列的个数。最后还要对答案进行处理,保证其为正数。

代码如下:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>

typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MAXN = 110;
const LL MOD = 1e9+7;
using namespace std;

LL dp[MAXN][MAXN];//dp[i][j]表示在区间(i,j)所有的子区间
char op[MAXN];
LL S[MAXN];//计算阶乘
LL C[MAXN][MAXN];//计算组合数


int n;
int main()
{
    S[0]=1;
    for(int i=1; i<=100; i++)
      S[i]=(S[i-1]*i)%MOD;
    C[0][0]=1;
    for(int i=1; i<=100; i++)
    {
        C[i][0]=1;
        for(int j=1; j<=100; j++)
        {
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD;//组合数公式
        }
    }
    while(scanf("%d",&n)!=-1)
    {
        memset(dp,0,sizeof(dp));
        for(int i=1; i<=n; i++)
        {
            scanf("%lld",&dp[i][i]);
        }
        scanf("%s",op+1);
        for(int l=2; l<=n; l++)//区间长度
        {
            for(int i=1; i+l-1<=n; i++)//区间起点
            {
                int j=i+l-1;//终点
                for(int k=i; k<j; k++)//枚举第k个运算符
                {
                    if (op[k]=='*') 
                       dp[i][j]+=(dp[i][k]*dp[k+1][j])%MOD*C[j-i-1][k-i]%MOD;
                    dp[i][j]%=MOD;
                    if (op[k]=='+') 
                       dp[i][j]+=(dp[i][k]*S[j-k-1]+dp[k+1][j]*S[k-i])%MOD*C[j-i-1][k-i]%MOD;
                    dp[i][j]%=MOD;
                    if (op[k]=='-') 
                       dp[i][j]+=(dp[i][k]*S[j-k-1]-dp[k+1][j]*S[k-i])%MOD*C[j-i-1][k-i]%MOD;
                    dp[i][j]%=MOD;
                }
            }
        }
        while(dp[1][n]<0) dp[1][n]+=MOD;
        printf("%lld\n",dp[1][n]%MOD);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值