CF425A Sereja and Swaps(暴力枚举+贪心)题解
题意
给一个长为 \(n\) 的序列,以及交换次数 \(k\),每次可以在原先的序列 中任意交换两个数 交换后找一个最大子串和,输出其可能的最大值。 \(1 \leq n \leq 200; 1 \leq k \leq 10\)。
算法
暴力枚举+贪心
思路(心路历程)
拿到题第一下还想这最大字段和DP什么的(雾),后来发现然而并不能消除后效性……
其实这题还是很良心的
暴力枚举每一段区间,考虑怎样交换能使答案最优,显然每次都要要用区间外的最大值来换区间内的最小值(前提条件是外最大值大于内最小值!),用堆维护最值即可。根本不用担心时间
复杂度
\(O(n^3 \log n)\).迷之复杂度
代码
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
int n,k,a[210],ans;
priority_queue<int, vector<int>, greater<int> > q1,kk;
priority_queue<int, vector<int>, less<int> > q2,kkk;
int main(){
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; ++ i) scanf("%d", a + i);
ans = -0x3f3f3f3f;
for(int l = 1; l <= n; ++ l)
for(int r = l; r <= n; ++ r){
q1 = kk, q2 = kkk;
int num = k, sum = 0;
for(int i = 1; i <= n; ++ i){
if(i >= l && i <= r) q1.push(a[i]);
else q2.push(a[i]);
}
while(num -- && !q2.empty()){
int top = q2.top(); q2.pop();
int ttop = q1.top();
if(ttop >= top) break;
q1.pop(); q1.push(top);
}
while(!q1.empty()) sum += q1.top(), q1.pop();
ans = max(ans, sum);
}
printf("%d\n", ans);
return 0;
}