Expression
分类:区间dp、组合数学
1.题意概述
- 给你 n(2≤n≤100) 个数和对应 (n−1) 个操作符,你每次给操作符相邻两个数加括号直到运算结束,问你最终的方案结果数的和,答案模 109+7 。
2.解题思路
n个操作符,计算顺序的排列组合有 n! 种,根据n的范围显然搜索的复杂度是不能接受的,我们考虑区间dp: dp[i][j] 为第i个数到第j个数的所有方案结果数的和,那么假设我们已经枚举到了区间 [i,j] 考虑第 k(i≤k≤j) 个操作符:
加法的转移方程:
dp[i][j]=∑Ck−ij−(i+1)(dp[i][k]⋅[j−(k+1)]!+dp[k+1][j]⋅(k−i)!)
- 阶乘表示加号左右侧的结果排列数,组合数表示区间取哪 (k−i) 个数当作左侧!
减法的转移方程:
dp[i][j]=∑Ck−ij−(i+1)(dp[i][k]⋅[j−(k+1)]!−dp[k+1][j]⋅(k−i)!)
乘法的转移方程: dp[i][j]=∑Ck−ij−(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;
}