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。

 

分析

  

  • 首先我们直接全部减一,答案就是s1*s2了
  • WHY??
  • 我们取k1数,又减去k1个数,不就等于每个数减一吗
  • 然后我们就分析怎么样去才是最小的呢
  • 因为答案是乘积,两个越大,答案就越大
  • 所以一次取一个是最好的
  • 但是数列的位数是不一定的
  • 所以我们要分情况讨论
  • f[i][j]为第一列删掉了i个,第二列删掉了j个
  • 因为每次取一个是最好的
  • 所以f[i][j]=f[i-1][j-1]+a[i]*a[j]
  • 然后就是第一列多取 f[i][j]=f[i-1][j]+a[i]*b[j]
  • 因为a*(b+c)=a*b+a*c
  • 所以因为我们f[i-1][j]中已经有a*b了
  • 所以我们还是只需要加上a[i]*b[j]

 

代码

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 int a[100001],b[100001];
 5 int f[2010][2011];
 6 int main ()
 7 {
 8     int n,m;
 9     cin>>n>>m;
10     memset(f,0x3f,sizeof(f));
11     f[0][0]=0; 
12     for (int i=1;i<=n;i++)
13        cin>>a[i],a[i]--;
14     for (int i=1;i<=m;i++)
15        cin>>b[i],b[i]--;
16     for (int i=1;i<=n;i++)
17       for (int j=1;j<=m;j++)
18         f[i][j]=min(f[i-1][j-1],min(f[i-1][j],f[i][j-1]))+a[i]*b[j];
19     cout<<f[n][m];
20  } 

 

 

posted @ 2019-07-04 21:15  Melted_czj  阅读(132)  评论(0编辑  收藏  举报
body { background-color:whitesmoke; } // 修改背景颜色为半透明 #home,#sideBarMain>div,#blog-sidecolumn>div>div,.catListView{ background-color:rgba(255,255,255,0); } // 修改其他边框的颜色