码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 5396 Expression

时间:2015-08-19 16:50:50      阅读:139      评论:0      收藏:0      [点我收藏+]

标签:

题意:给出一个式子,你可以将里面的运算符标上不同的优先级,然后按照优先级运算,问,不同的标法的所有结果的和是多少。


做法:

http://www.cnblogs.com/chenchengxun/p/4741439.html

这个链接解释的比较清楚了,关于最后乘以组合数那里,我再补充一下。


这个其实就是区间DP了
dp[i][j] 代表的是区间  i 到 j 的和
枚举dp[i][j] 之间所有的子区间
假如是乘法:
t = dp[i][k] * dp[k+1][j];
这个其实可以直接算出来的:
假设我们dp[i][k] 里面所有的值是 (x1+x2+x3...xn) == dp[i][k]
假设我们dp[k+1][j] 里面所有的值是 (y1+y2+y3...yn) == dp[k+1][j]
dp[i][k] * dp[k+1][j] == (x1+x2+...xn) * (y1+y2+y3...yn) == x1*y1+x1y*y2......xn*yn 其实和所有不同结果相乘出来是一样的
 
假如是加法或者减法:
我们表示阶乘 i为A[i].
t = dp[i][k]*A[j-k-1] + dp[k+1][j]*A[k-i];
其实这里我们想一下。区间 dp[i][k] 需要加上多少次?
我们需要加的次数就是另一半区间的所有组合数,另一半区间有多少种组合方式我们就要加上多少个。
因为他们之间可以相互组成不同的种类。同理另一半也是。
 
最后的时候我们要乘上一个组合数。
假设组合数为C[i][j].
为什么要乘组合数:
因为 假如我们k 分割了两个运算式子   【 1+(2*3)  】 + 【 1+(3*4) 】
虽然说我们左右两边的式子运算顺序已经确定了,但是我们总的运算顺序还是不确定的, 
比如我们算完(2*3) 再算(3*4),跟算完(3*4)再算(2*3)是不一样的,也就是说虽然结果一样,但是当成不一样的,因为优先级安排不一样。
dp[i][j] = dp[i][j] + t*C[j-i-1][k-i]
这个其实就是从总的运算符(j-i),减去了第k个的运算符,也就是(j-i-1)个,然后从中选取(k-i)个进行运算。
这里可以这样理解,如果不考虑总体顺序,直接从左算到右边,那么很显然是左边k-i个运算符比右边j-k-1个运算符先进行运算,这样就可以想到,考虑总体就是从j-i-1个运算符中挑选k-i个运算符首先进行运算,再运算剩下的j-k-1个运算符,于是就是乘上组合数的原因。


#include<map>
#include<string>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
#include<bitset>
#include<climits>
#include<list>
#include<iomanip>
#include<stack>
#include<set>
using namespace std;
typedef long long ll;
const ll mod=1000000007;
int a[110];
ll fac[110];
ll c[110][110],dp[110][110];
void create()
{
	fac[0]=1;
	for(int i=1;i<=100;i++)
		fac[i]=fac[i-1]*i%mod;
	for(int i=0;i<=100;i++)
		for(int j=0;j<=i;j++)
			if(j==0)
				c[i][j]=1;
			else
				c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
char op[110];
int main()
{
	int n;
	create();
	while(scanf("%d",&n)!=EOF)
	{
		for(int i=0;i<n;i++)
			scanf("%d",a+i);
		scanf("%s",op);
		for(int i=1;i<=n;i++)
			for(int j=0;j+i-1<n;j++)
			{
				int r=i+j-1;
				if(i==1)
				{
					dp[j][r]=a[j];
					continue;
				}
				dp[j][r]=0;
				for(int k=j;k<r;k++)
				{
					ll t;
					if(op[k]=='*')
						t=dp[j][k]*dp[k+1][r]%mod;
					else if(op[k]=='+')
						t=dp[j][k]*fac[r-k-1]%mod+dp[k+1][r]*fac[k-j]%mod;
					else
						t=dp[j][k]*fac[r-k-1]%mod-dp[k+1][r]*fac[k-j]%mod;
					dp[j][r]=(dp[j][r]+t*c[i-2][k-j]%mod)%mod;
				}
			}
		printf("%d\n",int((dp[0][n-1]+mod)%mod));
	}
}

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 384    Accepted Submission(s): 218


Problem Description
Teacher Mai has n numbers a1,a2,?,anand n?1 operators("+", "-" or "*")op1,op2,?,opn?1, which are arranged in the form a1 op1 a2 op2 a3 ? an.

He wants to erase numbers one by one. In i-th round, there are n+1?i numbers remained. He can erase two adjacent numbers and the operator between them, and then put a new number (derived from this one operation) in this position. After n?1 rounds, there is the only one number remained. The result of this sequence of operations is the last number remained.


He wants to know the sum of results of all different sequences of operations. Two sequences of operations are considered different if and only if in one round he chooses different numbers.

For example, a possible sequence of operations for "1+4?6?8?3" is 1+4?6?8?31+4?(?2)?31+(?8)?3(?7)?3?21.
 

Input
There are multiple test cases.

For each test case, the first line contains one number n(2n100).

The second line contains n integers a1,a2,?,an(0ai109).

The third line contains a string with length n?1 consisting "+","-" and "*", which represents the operator sequence.
 

Output
For each test case print the answer modulo 109+7.
 

Sample Input
3 3 2 1 -+ 5 1 4 6 8 3 +*-*
 

Sample Output
2 999999689
Hint
Two numbers are considered different when they are in different positions.
 

Author
xudyh
 

Source



版权声明:本文为博主原创文章,未经博主允许不得转载。

HDU 5396 Expression

标签:

原文地址:http://blog.csdn.net/stl112514/article/details/47781581

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!