贪心/妙妙题单(三)(中等-困难)

CF 865D D. Buy Low Sell High

tag: 反悔贪心,贪心,妙妙题

建一个最小堆,从前往后按照顺序,对每个值判断:

  1. 如果当前值比堆顶值还小,则直接放入堆中(注意放入堆中不是买)

  2. 如果当前值比堆顶值大,则把堆顶弹出(在当前为止卖掉)。会有一种情况,在当前为止卖掉不如留到之后再卖。

对于情况二,设堆顶值,当前值,之后的更优值分别为 \(p_1,p_2,p_3\)

则如果现在卖掉,且再以现在的价格买入一个,留到 \(p_3\) 卖掉:\((p_3-P_2)+(p_2-p_1)\)

和直接把 \(p_1\) 留到 \(p_3\) 卖一样。所以,在情况 2 的弹出堆顶后,可以再插入一个 \(p_2\)。注意,这个 \(p_2\) 不是情况 \(1\)\(p_2\),所以这里需要插入两个 \(p_2\)

虽然插入两个,但是和题意不冲突,因为第一个 \(p_2\) 实质上是一个虚拟的东西

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int n;
    cin>>n;

    int ans=0;
    priority_queue<int,vector<int>,greater<int>> q;

    for(int i=1;i<=n;i++){
        int val;
        cin>>val;

        if(q.size() && val>q.top()){
            ans+=val-q.top();
            q.pop();
            q.push(val);
        }
        q.push(val);
    }

    cout<<ans;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    // cin>>ct;

    while(ct--){
        solve();
    }
}

CF 1110E Magic Stones

首先判断第一个数和最后一个数是否一样

将数组写成差分的形式:

\(a:\) \(a1,~~a1+d2,~~a1+d2+d3,~~a1+d2+d3+d4,~~...~~,~~a1+d1+d2+...+dn\)

会发现,对于 \(d\) 数组 \(d2-dn\) 而言,操作一次等价于交换 \(d\) 数组中某些位置的顺序

所以,如果 \(a,b\) 两个数组的 \(d\),排序后完全相同,则可以变过去

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int n;
    cin>>n;

    vector<int> a(n+1),b(n+1);
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int j=1;j<=n;j++){
        cin>>b[j];
    }

    if(a[1]!=b[1] || a[n]!=b[n]){
        cout<<"No\n";
        return;
    }

    vector<int> d1,d2;
    for(int i=2;i<=n;i++){
        d1.push_back(a[i]-a[i-1]);
        d2.push_back(b[i]-b[i-1]);
    }

    sort(d1.begin(),d1.end());
    sort(d2.begin(),d2.end());

    for(int i=0;i<d1.size();i++){
        if(d1[i]!=d2[i]){
            cout<<"No\n";
            return;
        }
    }

    cout<<"Yes\n";
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    // cin>>ct;

    while(ct--){
        solve();
    }
}

CF 1473C Array Destruction

注意到每次选两个数的时候,必须有当前最大值

所以,初始时一个数固定是最大值,\(O(n)\) 的枚举另一个数即可

总复杂度 \(O(n^2)\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

void solve(){
    int n;
    cin>>n;

    vector<int> a(2*n+1);
    multiset<int> st;

    for(int i=1;i<=2*n;i++){
        cin>>a[i];
        st.insert(a[i]);
    }

    sort(a.begin()+1,a.end());

    for(int i=1;i<2*n;i++){
        auto t=st;
        t.erase(t.find(a[2*n]));
        t.erase(t.find(a[i]));

        int x=a[2*n];
        vector<pii> ans;
        ans.push_back({a[2*n],a[i]});
        bool f=1;

        while(t.size()){
            int mx=*t.rbegin();
            t.erase(t.find(mx));
            int nd=x-mx;

            if(t.count(nd)){
                x=mx;
                ans.push_back({mx,nd});
                t.erase(t.find(nd));
            }
            else{
                f=0;
                break;
            }
        }

        if(f==0) continue;

        cout<<"YES\n";
        cout<<ans[0].first+ans[0].second<<endl;
        for(auto [x,y]:ans){
            cout<<x<<" "<<y<<endl;
        }
        return;
    }

    cout<<"NO\n";


}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;

    while(ct--){
        solve();
    }
}
posted @ 2026-03-17 16:16  LYET  阅读(17)  评论(0)    收藏  举报