HDU 5396 Expression (区间DP)

链接 : http://acm.hdu.edu.cn/showproblem.php?pid=5396

设d[i][j] 代表i~j的答案。区间DP枚举(i, j)区间的断点,如果断点处的操作符是‘*’,那么该区间的答案可以直接加上d[i][k] *  d[k+1][j],因为乘法分配律可以保证所有的答案都会乘起来。如果是加法,需要加的 就是 左边的答案 乘 右边操作数的阶乘 加上 右边的答案乘左边操作数的阶乘,最后要确定左边操作和右边操作的顺序 因为每个答案里是统计了该区间所有的阶乘情况,因此每一个左边已确定的顺序和右边已确定的顺序需要排列组合一下。比如:左边有3个操作数+-*,右边有2个操作符+-,当已经确定了他们各自的顺序,假设左边算-*+,右边+-,这个顺序已经固定,现在有五个操作符需要操作,我需要选择三个位置给左边的操作符-*+,那么右边的两个操作符自然就对应他们相应的位置。

另外:这个题目我的a数组只有开在一个特定的位置用G++才能过,,不知道为啥,(C++没这个情况,定义在哪都能AC)

下面的代码是G++和C++都能AC的代码:

/*--------------------- #headfile--------------------*/
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <cassert>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
/*----------------------#define----------------------*/
#define DRII(X,Y) int (X),(Y);scanf("%d%d",&(X),&(Y))
#define EXP 2.7182818284590452353602874713527
#define CASET int _;cin>>_;while(_--)
#define RII(X, Y) scanf("%d%d",&(X),&(Y))
#define DRI(X) int (X);scanf("%d", &X)
#define mem(a,b) memset(a,b,sizeof(a))
#define rep(i,n) for(int i=0;i<n;i++)
#define ALL(X) (X).begin(),(X).end()
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define RI(X) scanf("%d",&(X))
#define SZ(X) ((int)X.size())
#define PDI pair<double,int>
#define rson o<<1|1,m+1,r
#define PII pair<int,int>
#define MAX 0x3f3f3f3f
#define lson o<<1,l,m
#define MP make_pair
#define PB push_back
#define SE second
#define FI first
typedef long long ll;
template<class T>T MUL(T x,T y,T P){T F1=0;while(y){if(y&1){F1+=x;if(F1<0||F1>=P)F1-=P;}x<<=1;if(x<0||x>=P)x-=P;y>>=1;}return F1;}
template<class T>T POW(T x,T y,T P){T F1=1;x%=P;while(y){if(y&1)F1=MUL(F1,x,P);x=MUL(x,x,P);y>>=1;}return F1;}
template<class T>T gcd(T x,T y){if(y==0)return x;T z;while(z=x%y)x=y,y=z;return y;}
#define DRIII(X,Y,Z) int (X),(Y),(Z);scanf("%d%d%d",&(X),&(Y),&(Z))
#define RIII(X,Y,Z) scanf("%d%d%d",&(X),&(Y),&(Z))
const double pi = acos(-1.0);
const double eps = 1e-8;
const ll mod = 1000000007ll;
const int M = 100005;
const int N = 1005;
using namespace std;

/*----------------------Main-------------------------*/

int n;
ll d[N][N], c[N][N], a[N];
ll f[N];

char s[N];
void DP(int i, int j, int k) {
    int l = k - i, r = j - k - 1;
    ll ansl = d[i][k], ansr = d[k+1][j], tmp = 0;
    if(s[k] == '*') tmp = ansl * ansr;
    if(s[k] == '+') tmp = ansl * f[r] + ansr * f[l];
    if(s[k] == '-') tmp = ansl * f[r] - ansr * f[l];
    tmp = tmp % mod * c[l+r][l] % mod;
    d[i][j] = (d[i][j] + tmp) % mod;
}

void solve() {
    f[0] = 1;
    for(ll i = 1; i < N; i++) f[i] = f[i-1] * i % mod;
    for(int i = 0; i < N; i++) {
        c[i][0] = 1;
        for(int j = 1; j < N; j++) {
            c[i][j] = c[i-1][j] + c[i-1][j-1];
            c[i][j] %= mod;
        }
    }
    while(scanf("%d", &n) != EOF) {
        memset(a, 0, sizeof(a));
        for(int i = 1; i <= n; i++) cin >> a[i];
        scanf("%s", s+1);
        memset(d, 0, sizeof(d));
        for(int i = 1; i <= n; i++) d[i][i] = a[i];
        for(int len = 2; len <= n; len++) {
            for(int i = 1; i <= n - len + 1; i++) {
                int j = i + len - 1;
                for(int k = i; k < j; k++) DP(i, j, k);
            }
        }
        cout << (d[1][n]+mod) %mod << endl;
    }
}

int main() {
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt","w",stdout);
//    CASET
    solve();
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-15 08:48:44

HDU 5396 Expression (区间DP)的相关文章

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+

Hdu 2513 区间DP

Cake slicing Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 149    Accepted Submission(s): 86 Problem Description A rectangular cake with a grid of m*n unit squares on its top needs to be slice

HDU 5396 Expression (MUT#9 区间DP)

[题意]:click here~~ [题目大意]: 给你一个一行包含n(2=<n<=100)个数字的式子,和一个字符串(2=<s<=100),字符串里包含三种运算符号:+,-,*,且s=n-1,也就是说在每两个数字之间,插入n-1个符号,位置已经在输入的时候固定了,现在你要做的就是可以自由安排符号的运算顺序,每轮选择之后,将会得到一个结果,求所有的结果的和 [思路]:区间DP: 先贴一下题解(感觉题解有个地方写错了): 设DP[l][r]:表示区间[l,r]这段里面能形成的答案的总

HDU 5396 Expression(DP+组合数)(详解)

题目大意: 给你一个n然后是n个数. 然后是n-1个操作符,操作符是插入在两个数字之间的. 由于你不同的运算顺序,会产生不同的结果. 比如: 1 + 1 * 2 有两种  (1+1)*2   或者  1+(1*2) 1 *  2 * 3  也是两种即使结果是一样的  (1*2)*3  或者 1*(2*3) 问这所有不同的组合加起来的和对 1e9+7取余是多少. 这个其实就是区间DP了 dp[i][j] 代表的是区间  i 到 j 的和 枚举dp[i][j] 之间所有的子区间 假如是乘法: t =

HDU 5900(区间DP)

HDU 5900 QSC and Master 题意:给一串数的key和value,如果相邻两元素key不是互质的就可以将这俩移除并获得这俩的value值,移除后两侧的元素便是相邻了,问最终最大能获得多少value值. 思路:区间DP,区间长度为1时dp[i][i]为0,添加一个标记数组vis[i][j],记录区间内是否所有数字都为可以移除,每次处理需要讨论最后留下区间两侧的情况. #include <cstdio> #include <cstring> #include <

HDU 5396 Expression

传送门 区间DP,枚举最后一步操作k,对乘法,答案为 dp[i,k]?dp[k+1,r],由于分配率这个会乘开来. 如果是加法那么是dp[i][k]?(j?k?1)!+dp[k+1][j]?(k?i)!,减法同理. 最后还要乘以C(j?i?1,k?i) #include <bits/stdc++.h> using namespace std; #define prt(k) cerr<<#k" = "<<k<<endl typedef lo

[hdu5396 Expression]区间DP

题意:给一个表达式,求所有的计算顺序产生的结果总和 思路:比较明显的区间dp,令dp[l][r]为闭区间[l,r]的所有可能的结果和,考虑最后一个符号的位置k,k必须在l,r之间,则l≤k<r,dp[l][r]=Σ{dp[l][k]?dp[k+1][r]}*(r-l-1)!/[(k-l)!(r-k-1)!],其中(r-l-1)!/[(k-l)!(r-k-1)!]表示从左区间和右区间选择符号的不同方法总数(把左右区间看成整体,那么符号的选择在整体间也有顺序,内部的顺序不用管,那是子问题需要考虑的)

HDU 5115 (区间DP)

题目大意:你是一个战士现在面对,一群狼,每只狼都有一定的主动攻击力和附带攻击力.你杀死一只狼.你会受到这只狼的(主动攻击力+旁边两只狼的附带攻击力)这么多伤害~现在问你如何选择杀狼的顺序使的杀完所有狼时,自己受到的伤害最小.(提醒,狼杀死后就消失,身边原本相隔的两只狼会变成相邻,而且不需要考虑狼围城环这种情况) 输入要求:总共T组数据,每组N只狼,按顺序输入全部狼的主动攻击力和然后再按顺序输入全部狼的附带攻击力 输出要求:Case #x: y x第几组数据,y最少受到的伤害. 思路:枚举当前区间

HDU 5568 sequence2 区间dp+大数

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5568 题意: 求所有长度为k的严格升序子序列的个数. 题解: 令dp[i][k]表示以i结尾的长度为k的所有严格升序子序列的个数,则有状态转移:dp[i][k]+=dp[j][k-1](其中,arr[i]>arr[j],并且i>j): 最后答案为dp[1][k]+...dp[n][k]. 代码: 1 import java.util.*; 2 import java.math.*; 3 publ