[DP]JZOJ 3046 游戏

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。

 

分析

对于$(k1-s1)*(k2-s2)$这个柿子,不难发现$k1-s1=\Sigma k-1$

所以事先给所有值-1,柿子变成$k1*k2=\Sigma k1_i\times\Sigma k2_i$

DP的柿子就是$f[i][j]=min(f[i+1][j],f[i+1][j+1],f[i][j+1])+a[i]*b[j]$

 

#include <iostream>
#include <cstdio>
#include <memory.h>
using namespace std;
const int N=2e3+10;
int l1,l2;
int a[N],b[N],f[N][N];

int main() {
    scanf("%d%d",&l1,&l2);
    for (int i=1;i<=l1;i++) scanf("%d",&a[i]),a[i]--;
    for (int i=1;i<=l2;i++) scanf("%d",&b[i]),b[i]--;
    memset(f,0x7f,sizeof f);
    f[l1+1][l2+1]=0;
    for (int i=l1;i;i--)
        for (int j=l2;j;j--)
            f[i][j]=min(f[i+1][j],min(f[i+1][j+1],f[i][j+1]))+a[i]*b[j];
    printf("%d",f[1][1]);
}
View Code

 

posted @ 2019-07-05 07:48  Vagari  阅读(213)  评论(0编辑  收藏  举报