CCC 2015 state1-s5 Greedy For Pies 糖果派 题解

目录

题目

Problem Description
The local pie shop is offering a promotion - all-you-can-eat pies! Obviously, you can’t pass up this
offer.
The shop lines up \(N\) pies from left to right - the ith pie contains \(A_i\) grams of sugar. Additionally,
another \(M\) pies are provided - the ith of these contains \(B_i\) grams of sugar.
You are first allowed to insert each of the \(M\) pies from the second group anywhere into the first list of \(N\) pies, such as at its start or end, or in between any two pies already in the list. The result will
be a list of \(N + M\) pies with the constraint that the initial \(N\) pies are still in their original relative order.
Following this, you are allowed to take one walk along the new line of pies from left to right, to pick up your selection of all-you-can-eat pies! When you arrive at a pie, you may choose to add it to your pile, or skip it. However, because you’re required to keep moving, if you pick up a certain pie, you will not be able to also pick up the pie immediately after it (if any). In other words, you cannot eat consecutive pies in this combined list.
Being a pie connoisseur, your goal is to maximize the total amount of sugar in the pies you pick up from the line. How many grams can you get?
Input Specification
The first line of input contains the integer \(N (1 ≤ N ≤ 3000)\) . The next \(N\) lines contain one integer \(Ai (1 ≤ Ai ≤ 10^5)\) , describing the integer number of grams of sugar in pie \(i\) in the group of \(N\) pies.
The next line contains \(M (0 ≤ M ≤ 100)\) , the number of pies in the second list. The next \(M\) lines contain one integer \(Bi (1 ≤ Bi ≤ 10^5)\) , describing the integer number of grams of sugar in pie \(i\) in the group of \(M\) pies.
For \(20\%\) of the marks for this question, \(M = 0\). For another \(20\%\) of the marks for this question \(M = 1\) . For another \(20\%\) of the marks for this question \(M ≤ 10\) .
Output Specification
Output the maximum number of grams of sugar in all the pies that you are able to pick up.
Sample Input

5
10
12
6
14
7
11
3
1
8
2

Output for Sample Input

44

Explanation of Output for Sample Input
Place the pies in the order

\[10, 1, 12, 2, 8, 6, 14, 7 \]

(that is, insert the pie with \(1\) gram of sugar between \(10\) and \(12\), and insert pies with \(2\) and \(8\) grams of sugar, in that order, between pies \(12\) and \(6\)). Then, we can grab \(10 + 12 + 8 + 14 = 44\) grams of sugar, which is maximal.

题目翻译

有两个糖果序列,分别为 \(a_i\) 和 \(b_i\) ,长度分别为 \(N\) 和 \(M\) ,每个糖果都有一个美味值。现在你要将 \(b_i\) 插入 \(a_i\) ,使之成为一个长度为 \(N+M\) 的序列,插入规则:
你可以将每个 \(b_i\) 插入 \(a_i\) 的任意位置。(也就是说,\(b_i\) 的原始顺序可以打乱,但是 \(a_i\) 的相对顺序不变)
接下来,你要在合并好的序列中选取一些糖果,只是不能连续选取糖果,求一种合并方案,使得能够选取的糖果美味值总和最大。

题目解析

暴力方法:对于每个 \(b_i\) 枚举插入点,最后做一遍DP就可以了,算法复杂度 \(\Theta\left(M^N\left(M+N\right)\right)\) 超时。
考虑贪心,我们发现贪心的做法显然是错误的。
我们发现题目没有要求输出路径,那么可以考虑DP。

DP式

我们发现在取糖果的时候不能连续取,那么我们将 \(b\) 数组进行升序排序,这样就可以让 \(b\) 数组的前一部分一定不取,后面的可以取也可以不取。
令函数\(f(i,j,k,0/1)\) 代表 \(a_{1\to i}\ b_{1\to j,k\to m}\ a_i\)和\(b_k\) 不取/取。\(b\) 升序。
不难得到:

\[f(i,j,k,0)=\max\left(\ f(i,j-1,k,0)\ ,\ f(i,j-1,k,1)\ ,\ f(i-1,j,k,1)\ ,\ f(i-1,j,k,0)\ \right) \]

\[f(i,j,k,1)=\max\left(\ f(i-1,j,k,0)+a_i\ ,\ f(i,j,k+1,0)+b_{k}\ \right) \]

解释:第一行第一个和第二个代表加了一个\(b_j\)来垫,第三第四个代表加上了 \(a_i\) 但是没有使用。
第二行第一个代表加上一个 \(a_i\) ,一个加上 \(b_k\) 。

细节

DP式搞定了,还要看一下怎么迭代。
初始值很简单,全部是 \(0\) 就可以了。
考虑循环的范围,因为要考虑到全部用来垫的情况和全部使用的情况,所以伪代码如下:

for i=1 to n
for j=0 to m+1
for k=m+1 to k

最后统计最大值即可,至于\(f(n,0,0,1),f(n,0,0,0)\) 和 \(f(n,m+1,m+1,1),f(n,m+1,m+1,0)\)。统计不统计都无所谓,因为它们不可能是最大的,最多会和最大值相等,不会影响结果

代码

#include<cstdio>// https://www.luogu.com.cn/paste/ci11vsqa
#include<algorithm>
#define maxn 3039
#define maxm 139
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int f1[maxn],f2[maxn];
int f[maxn][maxm][maxm][2];
int a[maxn],b[maxm];
int n,m;
int main(){
	//freopen("candy.in","r",stdin);
	//freopen("candy.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
        scanf("%d",&b[i]);
    if(m==0){
    	f1[0]=f1[0]=0;
    	for(int i=1;i<=n;i++){
	    f1[i]=f2[i-1]+a[i];
		f2[i]=max(f1[i-1],f2[i-1]);
	    }
	    printf("%d",max(f1[n],f2[n]));
	    return 0;
	}
	sort(b+1,b+m+1);
	for(int i=1;i<=n;i++)
    for(int j=0;j<=m+1;j++)
    for(int k=m+1;k>=j;k--){
        f[i][j][k][0]=max(f[i-1][j][k][1],f[i-1][j][k][0]);
        if(j) f[i][j][k][0]=max(f[i][j][k][0],max(f[i][j-1][k][0],f[i][j-1][k][1]));
        f[i][j][k][1]=max(f[i-1][j][k][0]+a[i],f[i][j][k+1][0]+b[k]);
        //else f[i][j][k][1]=f[i-1][j][k][0]+a[i];
	}
	int maxx=-1;
	for(int i=0;i<=m;i++)
	    maxx=max(maxx,max(f[n][i][i+1][1],f[n][i][i+1][0]));
	printf("%d",maxx);
	return 0;
}
上一篇:论状态机的实际应用:


下一篇:Reading27. Income Taxes