题意:一个表达式,加不同的括号得到不同的计算顺序,只要有一个计算顺序不同这两个表达式就是不同的。求所有表达式的和。
区间dp +排列组合
一开始我就知道大概可以用区间dp解决,开个二维记录区间[l,r]的所有方案的总和,然后枚举最后一次操作的符号,把每个区间分为两半,因为左边区间的总和可能有几种情况相加而得到a1,a2,a3,我们把其和保存在数组d【l】【k】,k是枚举的,代表最后操作符号的位置,因为原区间【l】【r】的dp值涉及到每个两个小区间【l】【k】、【k+1】【r】的方案数。例如
A(a,b,c) + B(d,e)
由于我们要求每种可能
那么将产生
a+db+dc+d
a+eb+ec+e
可以发现其等价于 2A + 3B A里面的元素都加了两次,B里面的元素都加了3次
转:http://blog.csdn.net/corncsd/article/details/47758975
dp[l][r]的计算方法是枚举最后一个被计算的位置i,设n1=dp[l][i],n2=dp[i+1][r],t1=t[l][i],t2=t[i+1][r]。那么对于加号,对于每个i要加上n1*t2+n2*t1,对于右边不同的组合,左边的数每次都要被加一次,同理左边不同的组合,右边的数每次也要被加一次。因此n1被加了t2次,n2被加了t1次。减法和加法一样。乘法是直接n1*n2。
当时忘记下面的了。。。。。。。
这还没完, 注意就算是左边的顺序和右边的顺序的确定,假设左边有f1个符号,右边有f2个符号,也有C[f1+f2][f1]种排法,相当于在f1+f2个位置中选f1个,剩下的给f2,f1和f2中排列的相对顺序不改变,所以还要乘上C[f1+f2][f1]。同理对于每个i,t[l][r]要加上t1*t2*C[f1+f2][f1]。
转:http://blog.csdn.net/corncsd/article/details/47758975
dp[l][r]的计算方法是枚举最后一个被计算的位置i,设n1=dp[l][i],n2=dp[i+1][r],t1=t[l][i],t2=t[i+1][r]。那么对于加号,对于每个i要加上n1*t2+n2*t1,对于右边不同的组合,左边的数每次都要被加一次,同理左边不同的组合,右边的数每次也要被加一次。因此n1被加了t2次,n2被加了t1次。减法和加法一样。乘法是直接n1*n2。
当时忘记下面的了。。。。。。。
这还没完, 注意就算是左边的顺序和右边的顺序的确定,假设左边有f1个符号,右边有f2个符号,也有C[f1+f2][f1]种排法,相当于在f1+f2个位置中选f1个,剩下的给f2,f1和f2中排列的相对顺序不改变,所以还要乘上C[f1+f2][f1]。同理对于每个i,t[l][r]要加上t1*t2*C[f1+f2][f1]。
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
int inf= 1<<30;
int v[110];
int w[110];
int d[102][1100][33];
using namespace std;
int main()
{
int i,j,k,n,m,T,K,N,V,m1,m2,t;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&N,&V,&K);
for(i=0;i<=N;i++){
for(j=0;j<=V;j++){
for(k=1;k<=30;k++)
{
d[i][j][k]=-inf;
}
}
}
for(i=1;i<=N;i++)
scanf("%d",&w[i]);
for(i=1;i<=N;i++)
scanf("%d",&v[i]);
for(j=V;j>=0;j--)
{
if(j>=v[i])
d[1][j][1]=w[1];
else d[1][j][1]=0;
}
for(i=2;i<=N;i++)
{
for(j=V;j>=1;j--)
{
m1=m2=1;
for(k=1;k<=K;k++)
{
t=d[i-1][j][m1];
if(j>=v[i]&&d[i-1][j][m1]<d[i-1][j-v[i]][m2]+w[i])
{
t=d[i-1][j-v[i]][m2]+w[i];
m2++;
}
else m1++;
d[i][j][k]=t;
}
}
}
int ans=d[N][V][K];
if(ans<0)
ans=0;
printf("%d\n",ans);
}
return 0;
}