双向队列 枚举模拟
Problem Statement
有 N 块羊肉穿在同一根竹签上,从左到右美味值 依次为 V1, V2, …, VN。注意美味值可能为负数。
现在你想把一些羊肉夹到自己的盘子里。
你至多可以进行 K 次操作,可选择的操作如下:
操作 A:将羊肉串上最左端的羊肉夹到盘子中,必须保证羊肉串上有羊肉
操作 B:将羊肉串上最右端的羊肉夹到盘子中,必须保证羊肉串上有羊肉
操作 C:将盘子中的某块羊肉重新穿到羊肉串的最左端,必须保证盘子中有羊肉
操作 D:将盘子中的某块羊肉重新穿到羊肉串的最右端,必须保证盘子中有羊肉
找出夹到盘子中的羊肉的美味值之和的最大可能。
Constraints
所有输入的值都是整数
1 ≤ N ≤ 50
1 ≤ K ≤ 100
-107 ≤ Vi ≤ 107
Input
输入按以下格式由 标准输入 给出:
N K
V1 V2 … VN
Output
输出夹到盘子中的羊肉的美味值之和的最大可能。
Sample Input 1
6 4
-10 8 2 1 2 6
Sample Output 1
14
通过以下操作,你将会得到两块美味值分别为 8 和 6 的羊肉,总和 14 为最大值。
操作 A,把美味值为 -10 的羊肉夹到盘中
操作 B,把美味值为 6 的羊肉夹到盘中
操作 A,把美味值为 8 的羊肉夹到盘中
操作 D,把美味值为 -10 的羊肉穿回羊肉串的右端
Sample Input 2
6 4
-6 -100 50 -2 -5 -3
Sample Output 2
44
Sample Input 3
6 3
-6 -100 50 -2 -5 -3
Sample Output 3
0
什么都不做才是最优的。
分析
本题双端队列意为从数组的两端选择/插入元素,并求所得元素集合之和的最大值.
预处理:
输入元素可用数组存储,而对数组元素的双端操作可采用两个变量 i , j 前后访问;
而中间的元素集合可用数组存储;
根据N和Vn的数据范围可得int 不会越界,最后结果可定义一个最大值int变量.
枚举过程:
枚举的重点在于找出一般的状态.
本题有四种操作,取左端/取右端/放左端/放右端.
取数一定在放数之前,如果我们把相同的处理过程归类,
则过程可以简化为:先取数,后放数.
由于取数对次序要求严格,而放数不会影响最终结果,因此共有三种状态过程.
-
取左端
-
取右端
-
放数
需要注意的是,负数会产生副作用.
我们在放数过程,只需要尽可能多(范围限制)得处理掉影响大的负数(排序).
假设从左端取l个数,右端r个数,在进行k次放数操作则有
int i,j;
for(i=0;i<l;i++)
plate[i]=mutton[i];
for(j=0;j<r;j++)
plate[i+j]=mutton[N-j-1];
sort(plate,plate+l+r);//依次处理掉影响大的元素
int k=0,temp=0;
while(k+l+r<K&&plate[k]<0)//至多进行K次操作,则放数次数k满足一定条件
k++;
while(k<l+r)//求得处理后序列元素之和
{
temp+=plate[k];
k++;
}
一般状态找到了,再可对整体进行范围限制;
l,r之和必须小于等于元素总数N;l,r,k之和并且小于等于操作总数K;
l+r+k<=K,l+r<=N
对l和r的每种可能取值,都要进行一次上述过程,并且找出最大值.
int bound=min(N,K);
for(int l=0;l<=bound;l++)
{
for(int r=0;r<=bound-l;r++)
{
/*上述状态处理
int i,j;
for(i=0;i<l;i++)
plate[i]=mutton[i];
for(j=0;j<r;j++)
plate[i+j]=mutton[N-j-1];
sort(plate,plate+l+r);
int k=0,temp=0;
while(k+l+r<K&&plate[k]<0)
k++;
while(k<l+r)
{
temp+=plate[k];
k++;
}
*/
res=max(res,temp);
}
}
代码实现:
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 51
int mutton[MAXN];
int plate[MAXN];
int main()
{
int N,K,res=0;
cin>>N>>K;
for(int i=0;i<N;i++)
cin>>mutton[i];
int bound=min(N,K);
for(int l=0;l<=bound;l++)
{
for(int r=0;r<=bound-l;r++)
{
int i,j;
for(i=0;i<l;i++)
plate[i]=mutton[i];
for(j=0;j<r;j++)
plate[i+j]=mutton[N-j-1];
sort(plate,plate+l+r);
int k=0,temp=0;
while(k+l+r<K&&plate[k]<0)
k++;
while(k<l+r)
{
temp+=plate[k];
k++;
}
res=max(res,temp);
}
}
cout<<res<<endl;
return 0;
}