3046. 【NOIP2012模拟10.23】游戏

Description

游戏规则如下:给定两个正整数数列,一个游戏者通过若干次操作完成游戏。每一次操作,选择两个正整数k1和k2。将第一个数列的最后连续k1个数删除,它们的和记为S1;将第二个数列的最后连续K2个数删除,它们的和记为S2。这一次操作的得分就是(S1-K1)* (S2-K2 )。直到两个数列都清空了为止,所以不允许一个数列空了,而另一个数列中还有数。游戏的总得分就是每一次操作的得分总和。求最小的总得分。 

 

Input

第一行是两个整数L1和L2,分别表示第一个数列和第二个数列的初始长度。 

 

第二行有L1个正整数,是第一个数列的数。 

 

第三行有L2个正整数,是第二个数列的数。 

 

数列中的数都不超过1000。 

 

Output

一个整数,表示最小的总得分。 

 

Sample Input

3 2
1 2 3
1 2

Sample Output

2

Data Constraint

Hint

对于20%的数据,L1,L2<=20; 

 

对于40%的数据,L1,L2<=200;

 

对于100%的数据,1<=L1,L2<=2000。

Solution

暴力:

设f[i][j]表示第一个数列取了前i个,第二个数列取了前j个的最小得分(正着做和倒着做是一样的)。F[i][j]=F[k][l]+sum(s[i]-s[k]-(i-k))*(s[j]-s[l]-(j-l))。时间复杂度O(n^4)。
其实可以发现因为数列中的数都是正整数,所以(a+c)*(b+d)>a*b的,其中a、b分别为第一列,第二列选的数,c、d为下一次选的数,由此我们知道尽量一个一个选是最优的,但是不免会有1对多的情况,至此F[ i ] [j ]={ F[ i-1 ][ j-1 ], F[ i-1 ][ j ] ,F[ i ][ j-1 ] }+(a[ i ]-1)*(b[ j ]-1)。(它由a[i]*b[j],和(第一列上一段+a[i])*第二列上一段,a[i]*(第二列上一段+b[j])推来)

Code

#include
#include
#include
#define N 2010
using namespace std;
int n,m,a[N],b[N],sa[N],sb[N],f[N][N],p;
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i]--;
	for(int i=1;i<=m;i++) scanf("%d",&b[i]),b[i]--;
	memset(f,127,sizeof(f));
	f[0][0]=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			f[i][j]=min(f[i-1][j-1],min(f[i][j-1],f[i-1][j]))+a[i]*b[j];
		}
	}
	printf("%d\n",f[n][m]);
	return 0;
}


作者:zsjzliziyang 
QQ:1634151125 
转载及修改请注明 
本文地址:https://blog.csdn.net/zsjzliziyang/article/details/94621774

你可能感兴趣的:(题目,dp)