做这道题的时候,想到会不会是dp,然后发现dp可做,但是一直被自己坑到死。
枚举最后合并的那个位置,然后对于加减号的,分成的前后两个部分都有不同的组合方法,
(a1+a2........) + (b1,b2.............) 对于每个a,被加b的个数的阶乘次 ,对于每个b,被加a的个数的阶乘次
减法同理
乘法特殊一点
(a1+a2........) * (b1,b2.............) 乘法分配率,直接将两部分的总和相乘即可
想到这些还远远没有结束,因为最后两个区间合并的时候,还牵扯到一个顺序问题,一开始还好傻好天真直接乘了2,结果呵呵哒了。
如果共有N个符号,i左边x个,右边y个,那么因为枚举了i这个最后合并的位置,所以最后一个进行运算的符号是确定的,处理完左右的得出的数字分别被加过多少次之后,还要处理这个得出的总数因为合并的顺序不同被多加过多少次,就是C(N-1,x) 其中选出的这x个位置中保持i左边符号的相对顺序不变,因为之前变过顺序的那个前面已经处理过了。。自己理解这里一开始有点问题,总是混,特别怕dp计数,尤其跟排列组合混起来,感觉脑子差一截……
#pragma comment(linker,"/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <string>
#include <map>
#include <utility>
#include <algorithm>
#include <iostream>
#define mem(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f
using namespace std;
int dx[]= {-1,0,1,0};///n e s w
int dy[]= {0,1,0,-1};
typedef long long ll;
typedef pair<int,int> pii;
const int maxd=200+5;
///==============================
const int mod=1000000007;
ll dp[maxd][maxd],a[maxd],fac[maxd],c[maxd][maxd];
int n;
char str[maxd];
void init()
{
fac[0]=1;
for(int i=1; i<maxd; i++)
fac[i]=fac[i-1]*i%mod;
mem(c,0);
for(int i=0; i<maxd; i++)
{
c[i][0]=1;
for(int j=1; j<=i; j++)
(c[i][j]=c[i-1][j-1]+c[i-1][j])%=mod;
}
}
ll dfs(int l,int r)
{
ll &res=dp[l][r];
if(res!=mod) return res;
if(l==r)
return res=a[l];
res=0;
for(int i=l; i<r ; i++)
{
ll tmp;
if(str[i]=='*')
tmp=dfs(l,i)*dfs(i+1,r)%mod;
else if(str[i]=='-')
tmp=(dfs(l,i)*fac[r-i-1]-dfs(i+1,r)*fac[i-l]+mod)%mod;
else if(str[i]=='+')
tmp=(dfs(l,i)*fac[r-i-1]+dfs(i+1,r)*fac[i-l])%mod;
res=(res+tmp*c[r-l-1][i-l]+mod)%mod;
}
return res;
}
int main()
{
int kase;
freopen("in.txt","r",stdin);
init();
while(scanf("%d",&n)!=EOF)
{
for(int i=0; i<n; i++)
scanf("%lld",&a[i]);
scanf("%s",str);
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
dp[i][j]=mod;
cout<<(dfs(0,n-1)+mod)%mod<<endl;
}
return 0;
}
/*
3
3 2 1
-+
5
1 4 6 8 3
+*-*
5
1 1 1 1 1
****
*/