HDU 5396 Expression (区间DP)

来源:互联网 发布:淘宝怎么更改追加评价 编辑:程序博客网 时间:2024/06/09 13:52

链接 : 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 firsttypedef 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;}



1 0