http://www.codeforces.com/contest/182/problem/C
题意:给你一组有N个数的数列,给你最多K次将其中的一个数取反 的机会,即原来是a的数,经过这种操作之后,这个数会变成-a。问在最多允许k次这种操作的情况下,最大的连续len个数的sum是多少。N<=100000
思路:这是一道3000分的题,比赛的时候没做出来,是比了赛之后看别人的代码之后才想明白的。题意很容易理解,只是在len中将取反的名额分给谁是一个需要我们决策的问题,我们可以这样想,如果这len个中,负数的个数小于k个的话,我们可以直接将这几个负数全部取反,这样就可以达到最大sum;现在考虑len区间内的负数的个数大于k个,这就要求我们选择绝对值最大的k个将负数取反,这样的和也是最优的,这样的话我们就把问题转换成了在len个元素中选出绝对值前k大的值,这个操作我们可以用一个优先队列实现,复杂度为:O(logn)。接下去我们将区间先后移动一步,这样就会将一个元素移出,一个元素移入,移出的元素我们需要判断是否是取反的元素,因此我们还需要用一个数组标记每个负数是否取反了。考虑移入区间的新元素,如果是正数,则加上;如果是负数,就要考虑是否取反,这里当然也是要考虑将现在len区间内绝对值前k个大的元素取反,一开始这个地方没有考虑到, WA了。。
代码:
#include<stdio.h>
#include<string.h>
#include<queue>
#include<vector>
using namespace std;
typedef __int64 LL ;
const int MAXN = 100100;
const LL inf = 1000000000000000ll ;
LL n , len ,k ;
LL a[MAXN] ;
priority_queue< pair<LL,LL> ,vector< pair<LL,LL> > , greater< pair<LL,LL> > > que ;
priority_queue< pair<LL,LL> ,vector< pair<LL,LL> > , less< pair<LL,LL> > > que1;
bool vis[MAXN] ;
void solve(){
LL i ,j ,f , c ,v ,b;
LL ans = -inf ;
for(f=0;f<2;f++){ //最终的最大sum是正数还是负数
if(f == 1){
for(i=1;i<=n;i++){
a[i] = -a[i] ;
}
}
c = 0 ;
LL res = 0 ;
while(!que.empty()) que.pop() ;
memset(vis, 0 ,sizeof(vis));
while(!que1.empty()) que1.pop() ;
for(i=1;i<=n;i++){ //计算在最多k次操作的情况下,第一个len区间的最大和
if( a[i]<0 ){
if( c==k ){
if( !que.empty() && -a[i]>que.top().first ){
v = que.top().first ; //val
b = que.top().second ; //number
que1.push( make_pair(v,b) );
vis[b] = 0 ;
que.pop() ;
que.push( make_pair( -a[i] , i) ) ;
vis[i] = 1 ;
res -= 2*v ;
res -= a[i] ;
}
else{
res += a[i] ;
que1.push( make_pair( -a[i] , i) );
}
}
else{
que.push( make_pair(-a[i] , i));
vis[i] = 1 ;
c++ ;
res -= a[i] ;
}
}
else
res += a[i] ;
if(i == len) break ;
}
if(ans < res) ans = res ;
for(i++ ;i<=n;i++){ //移动区间
if( vis[i-len] == 1){
res += a[i-len] ;
c -- ;
}
else{
res -= a[i-len] ;
}
while(!que1.empty() && c!=k){
v = que1.top().first ;
b = que1.top().second ;
if(b <= i-len) que1.pop() ;
else{
res += v*2 ;
c++ ;
que1.pop() ;
que.push( make_pair(v,b) );
vis[b] = 1 ;
}
}
if( a[i] < 0 ){
if( c==k ){
while(!que.empty() && que.top().second <= i-len ){
que.pop() ;
}
if(!que.empty() && que.top().first < -a[i]){
v = que.top().first ;
b = que.top().second ;
vis[ b ] = 0;
que.pop() ;
que1.push( make_pair(v,b) ) ;
que.push( make_pair(-a[i] , i)) ;
vis[i] = 1;
res -= 2 * v ;
res -= a[i] ;
}
else{
res += a[i] ;
que1.push( make_pair( -a[i] , i) );
}
}
else{
que.push( make_pair(-a[i] , i) ) ;
vis[i] = 1;
res -= a[i] ;
c++ ;
}
}
else{
res += a[i] ;
}
if( ans < res ) ans = res ;
}
}
printf("%I64d\n",ans);
}
int main(){
while(scanf("%I64d%I64d",&n,&len) == 2){
for(int i=1;i<=n;i++){
scanf("%I64d",&a[i]);
}
scanf("%I64d",&k);
solve() ;
}
return 0 ;
}