解题报告: 昨晚一直没想出来怎么做……一大憾事。写了个随机化一直WA,直接暴力也是一直超时……
今天看了队友的代码,发现思想还是很简单的:选定一个区间[i, j],则剩下的区间为[1, i-1]和[j+1, n],将选定区间的最小值与剩下区间的最大值交换,使选定区间的和越来越大。非常好的暴力方法啊。复杂度(n^2)*(nlogn + k*logn)。
清晰易懂的思路,简单易实现的代码,真是个非常好的“暴力”算法~
好吧,今天写的代码贴一个,用优先队列存储区间的最大值和最小值,最小值用一个数的负数获得,用的时候再反转就好了。
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
int num[222];
int sum[222];
void work(int n, int m)
{
for(int i=1;i<=n;i++)
{
scanf("%d", num+i);
sum[i]=sum[i-1]+num[i];
}
int ans=-1e8;
for(int i=1;i<=n;i++) for(int j=i;j<=n;j++)
{
int tmp=sum[j]-sum[i-1];
priority_queue<int> Max, Min;
for(int k=i;k<=j;k++) Min.push(-num[k]);
for(int k=1;k<i;k++) Max.push(num[k]);
for(int k=j+1;k<=n;k++) Max.push(num[k]);
for(int i=0;i<m && !Max.empty() && !Min.empty() && Max.top()+Min.top()>0;i++)
{
tmp+=Max.top()+Min.top();
Max.pop();
Min.pop();
}
ans=max(ans, tmp);
}
printf("%d\n", ans);
}
int main()
{
int n, k;
while(~scanf("%d%d", &n, &k))
work(n, k);
}