P9562 [SDCPC2023] Matching 题解

本蒟蒻的第一篇题解!!!

式子i−j=ai−aj,可以变式为i−ai=j−aj。

那么对于所有顶点 u,只有u−au相同的才会两两连边。这样整张图就形成了多个联通块。

对于每个联通块,就直接每次找最大值和次大值,把它们包含在答案里即可。 需要注意的是,如果两个点点权之和是负数,就不要选。利用容器动态存储数据,然后对每一个匹配项进行排序求和,求和的时候注意,若两点相加总和小于 0 需要舍弃。

Code:

#include <bits/stdc++.h>
#define int long long
#define IL inline 
using namespace std;
IL int read (){
        int x=0,f=1;
        char ch=getchar ();
        while(ch<'0'||ch>'9'){
            if(ch=='-')
                f=-1;
            ch=getchar ();
        }
        while(ch>='0'&&ch<='9'){
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar (); 
        }
        return x*f;
    }
IL void white (int x){
        if(x<0){
            x=-x;
            putchar('-');
        }
        if(x>9)
            white(x/10);
        putchar(x%10+'0');
}
IL void solve (){
        int n;
        n=read ();
        vector<int>w(n);
        for(auto&u:w)
            u=read ();
        vector<pair<int,int>>v(n);
        for(int i=0;i<n;i++)
            v[i]={w[i]-i,i};
        sort(v.begin(),v.end());
        int res=0;
        priority_queue<int>q;
        for(int i=0;i<n;i++){
            if(!i)
                q.push(w[v[i].second]);
            else
                if(v[i].first==v[i-1].first)
                    q.push(w[v[i].second]);
                else{
                    while(q.size()>=2){
                        int a,b;
                        a=q.top(),q.pop(),b=q.top(),q.pop ();
                        if(a+b>0)
                            res+=(a+b);
                    }
                    while(q.size())
                        q.pop();
                    q.push(w[v[i].second]);
                }
        }
        while (q.size()>=2){
            int a,b;
            a=q.top(),q.pop(),b=q.top(),q.pop();
            if(a+b>0)
                res+=(a+b);
        }
        white(res);
        puts("");
}
signed main(){
        int T;
        for(T=read();T;T --)
            solve();
        return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值