CF2063B Subsequence Update

Subsequence Update

题目翻译:

给定一个序列。在给定一个区间 \([l,r]\),你可以任意选择几个数,使所选的所有数左右颠倒。求如何颠倒才能使区间内的所有数之和最小。

思路:

若要使整个区间内所有数和最少,那一定就使尽量小的数翻转到区间内。我们发现我们只需要在区间左边或右边选择几个数,在在区间内选等量的数,翻转之后,所选的数就进去了。因此我们可以根据该性质。就可以发现,我们只需要在区间左边或右边选择较小的数与区间内较大的数替换即可。

实现:

可以建两个小根堆,分别储存区间加区间左边和区间加区间右边。然后只需要在两个小根堆中选择区间长度个数,在取最小值即可。这样所选择的就是最少答案。

完整代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int a[N];
priority_queue<int,vector<int>,greater<int>>q1,q2;
signed main(){
    int t;
    scanf("%lld",&t);
    while(t--){
        int n,l,r;
        scanf("%lld%lld%lld",&n,&l,&r);
        int len=r-l+1;
        while(!q1.empty())q1.pop();
        while(!q2.empty())q2.pop();
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            if(i<=r){
                q1.push(a[i]);
            }
            if(i>=l){
                q2.push(a[i]);
            }
        }
        int sum1=0,sum2=0;
        for(int i=1;i<=len;i++){
            sum1+=q1.top();
            sum2+=q2.top();
            q1.pop();
            q2.pop();
        }
        cout<<min(sum1,sum2)<<endl;
    }
}
posted @ 2025-01-23 13:48  XichenOC  阅读(107)  评论(0)    收藏  举报