3 3 2 1 -+ 5 1 4 6 8 3 +*-*
2 999999689HintTwo numbers are considered different when they are in different positions.
题意:给你n个数和n-1个操作符(2<=n<=100),问你不断地每次给操作符的左右相邻的两个数加括号,直到最后
只剩一个数为止,问你不同的方案的所有最终剩下一个数的和是多少。在一次取操作符时只要操作符的位置不相同就
算一种方案。
思路:这题主要在于状态转移方程。设dp[i][j]为第i个数到第j个数的所有方案的和,那么假设我们已经枚举到区间
i,j(i < j),对于加法和减法这两种情况是类似的,我们考虑第k个操作符(i<=k<j,假设k这个操作符是最后一次做
的,两边的操作符都已经完成了),有
若‘+’:
t= (dp[i][k] * A[j - (k + 1)] + dp[k + 1][j] * A[k - i] ) % mod
若‘-’:
t= (dp[i][k] * A[j - (k + 1)] - dp[k + 1][j] * A[k - i] ) % mod
若‘*’:
t= (dp[i][k] * dp[k + 1][j]) % mod
其中A数组储存阶乘值,C数组储存组合值。
为什么加法减法要乘以阶乘?对于左边的i到k来说,假设右边有n个符号,那么右边肯定有n!种方案,对于每个方案
都要加上左边的总和,所以要乘以一个阶乘。同理右边。。。。
为何乘法不需要阶乘?因为假设两边所有情况的最后一个数为(x1,x2,x3,……,xn)(y1,y2,y3……,yn),两边的所有情
况的和应该是
x1*y1+x1*y2+x1*y3……+x1*yn+x2*y1+x2*y2+x2*y3……+x2*yn+x3*y1+x3*y2+x3*y3……+x3*yn+………+xn*y1+xn*y2+xn*y3……+xn*yn,
然后化简之后得到的其实就是
(x1+x2+x3+……+xn)*(y1+y2+y3+……+yn)
最后的时候我们要乘上一个组合数。
dp[i][j] = (dp[i][j] + t*C[j-i-1][k-i])%mod;
为什么要乘组合数?因为k左边的是一个整体,k右边是一个整体,现在我们dp[i][j]这个整体区间是由左边和右边一起
得到,这意味着我们首先肯定要先计算左边所有的运算符,或者先计算右边所有的运算符,所以从所有可选符号里面
先选左边个,剩下的自然就是右边个,这样总个数才是正确的。
#include <iostream> #include <stdio.h> #include <stdlib.h> #include<string.h> #include<algorithm> #include<math.h> #include<stack> #include<queue> using namespace std; typedef long long ll; const int mod=1e9+7; int x[110]; char s[110]; ll dp[210][210]; ll A[110],c[110][110]; ll fdp(int a,int b) { if(dp[a][b]!=0)return dp[a][b]; if(a==b) return dp[a][b]=x[a]; for(int i=a; i<b; i++) { ll t=0; if(s[i]=='+') t=(fdp(a,i)*A[b-i-1]+fdp(i+1,b)*A[i-a])%mod; else if(s[i]=='-') t=(fdp(a,i)*A[b-i-1]-fdp(i+1,b)*A[i-a])%mod; else t=(fdp(a,i)*fdp(i+1,b))%mod; dp[a][b]=(dp[a][b]+t*c[b-a-1][i-a])%mod; } return dp[a][b]; } int main() { A[0]=1; for(int i=1; i<=100; i++) A[i]=(A[i-1]*i)%mod; for(int i=0; i<=100; i++) for(int j=0; j<=i; j++) if(j==0||j==i) c[i][j]=1; else c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod; int n; while(~scanf("%d",&n)) { memset(dp,0,sizeof(dp)); for(int i=0; i<n; i++) scanf("%d",&x[i]); for(int i=0; i<n-1; i++) scanf(" %c",&s[i]); cout<<(fdp(0,n-1)+mod)%mod<<endl; } return 0; }