hdu5396(2015多校9)--Expression(区间dp)

题目链接:点击打开链接

题目大意:有n个数,和n-1个符号('+','-','*')形成一个表达式,现在问对于不同的运算序列,得到的结果的总和是多少(结果为非负整数,对1e9+7取余)

dp[l][r]记录在区间l到r内的各种不同的运算序列的结果的和。

首先长度len是1的时候,dp[i][i] = a[i]

之后dp[l][r] = ∑ ( dp[l][j] 和 dp[j+1][r] 合并而成  ) j为[l,r]范围内的运算符号,那么分三种情况

1、'+'

对于dp[l][j]共有j-l个符号,也就是有(j-l)!种不同的运算序列,dp[j+1][r]有(r-j-1)!种运算序列,那么对于不同的运算序列得到的值应该累加,所以累加的和为dp[l][j]*(r-j-1)! + dp[j+1][r]*(j-l),同时还要注意,这种运算序列是符号j的左右两侧分开考虑的,如果交叉考虑,只要各自相对的运算顺序没变,那么值就不会变,但会形成新的一种运算方法,所以最终的值还要再乘以C(r-l-1 , j-l  )。

2、'-'

和加法基本相同,只需要把加换成减。

3、'*'

对于乘法,我们需要的结果是左右表达式中的各种运算方式得到的值分别相乘然后累加和,这个结果就可以直接转化为dp[l][j]*dp[j+1][r],同样我们还需要对最终的结果乘以C(r-l-1 , j-l)

注意取余,最终的dp[0][n-1]就是结果

#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <cmath>
#include <map>
#include <stack>
#include <time.h>
#include <algorithm>
using namespace std ;
#pragma comment(linker, "/STACK:102400000,102400000")
#define LL __int64
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
const int Mod = 1e9+7;
LL c[110][110] , s[110] ;
LL a[110] ;
LL dp[110][110] ;
char str[110] ;
void init() {
    int i , j ;
    for(i = 0 ; i <= 100 ; i++) {
        c[i][0] = c[i][i] = 1 ;
        for(j = 1 ; j < i ; j++)
            c[i][j] = (c[i-1][j]+c[i-1][j-1])%Mod ;
    }
    for(i = 1 , s[0] = 1 ; i <= 100 ; i++)
        s[i] = s[i-1]*i%Mod ;
    return ;
}
int main() {
    init() ;
    int n , i , j , len , l , r ;
    while( scanf("%d", &n) != EOF ) {
        for(i = 0 ; i < n ; i++)
            scanf("%I64d", &a[i]) ;
        scanf("%s", str) ;
        memset(dp,0,sizeof(dp)) ;
        for(i = 0 ; i < n ; i++) dp[i][i] = a[i] ;
        for(len = 2 ; len <= n ; len++) {
            for(i = 0 ; i+len-1 < n ; i++) {
                l = i ; r = i+len-1 ;
                for(j = l ; j < r ; j++) {
                    if( str[j] == '+' ) {
                        dp[l][r] = ( dp[l][r] + (dp[l][j]*s[r-(j+1)]%Mod+dp[j+1][r]*s[j-l]%Mod)*c[r-l-1][j-l]%Mod ) ;
                        dp[l][r] = (dp[l][r]%Mod+Mod)%Mod ;
                    }
                    else if( str[j] == '-' ) {
                        dp[l][r] = ( dp[l][r] + (dp[l][j]*s[r-(j+1)]%Mod-dp[j+1][r]*s[j-l]%Mod)*c[r-l-1][j-l]%Mod ) ;
                        dp[l][r] = (dp[l][r]%Mod+Mod)%Mod ;
                    }
                    else if( str[j] == '*' ) {
                        dp[l][r] = (dp[l][r] + dp[l][j]*dp[j+1][r]%Mod*c[r-l-1][j-l]%Mod) ;
                        dp[l][r] = (dp[l][r]%Mod+Mod)%Mod ;
                    }
                }
            }
        }
        printf("%I64d\n", dp[0][n-1]) ;
    }
    return 0 ;
}


你可能感兴趣的:(hdu5396(2015多校9)--Expression(区间dp))