CodeForces - 960B:Minimize the error(優先佇列+貪心)

想要「替身」的伊麗莎白aru發表於2020-11-20

連結https://vjudge.net/problem/CodeForces-960B

題意
輸入第一行的三個數字分別代表:n(每組各有n個數字,共有2組),k1(對第一組的操作次數),k2(對第二組的操作次數)。
所謂操作就是對一個數字進行 +1-1

操作k1+k2次之後對兩個陣列進行以下操作:

for(int i=0;i<n;i++)
    sum+=(a[i]-b[i])*(a[i]-b[i]);

求這個sum的最小值。

思路
狀態不是很好,主要是自己作了一個死(沒想到會出現那種東西,就整個人A完題還是濛濛的),所以導致精神不是很好,但還是順利A掉了。
在這裡插入圖片描述

我們先將對A,B陣列的操作轉移到一個陣列上面去:儲存A、B對應位置相減的絕對值的陣列C。這個時候操作次數就是k1+k2了。

然後再想,怎麼操作才會使結果最小呢?
其實我們的每次操作(無論對A還是B,無論是+1還是-1)都是讓C[i]減小。
這樣的話我們每次都讓差的絕對值最大的那個減1,這樣就能有效減小最終結果的值。

不要以為這就結束了,發問:如果此時C陣列裡全都是0,還剩下一些操作次數,怎麼辦?
(題目中要求是k1,k2全部用完哦`(∩_∩)′)

很簡單,讓C[0]加1,下一次最大的就是這個1,然後再讓它減1,重複此操作即可。

由於我們每一次都要讓最大的數-1,所以需要保持有序性。
這裡用的是優先佇列,建立一個降序的優先佇列q,儲存A、B對應位置相減的絕對值,替代C的存在。

直接看程式碼,伊麗莎白!

在這裡插入圖片描述
程式碼

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;  //坑1:開long long
const int maxn=1e6+100;
ll a[maxn];
int main()
{
    ll n,k1,k2,b,tmp;
    priority_queue <ll,vector<ll>,less<ll> > q;
    cin>>n>>k1>>k2;
    for(int i=0; i<n; i++)
        cin>>a[i];
    for(int i=0; i<n; i++)
    {
        cin>>b;
        a[i]=abs(a[i]-b);
        q.push(a[i]);
    }
    ll ss=k1+k2;
    while(ss--)
    {
        tmp=q.top();
        q.pop();
        q.push(abs(tmp-1));   //這一步你細品,細品(想一下q裡全為0,ss!=0的時候就明白了)
    }
    ll sum=0;
    while(!q.empty())
    {
        tmp=q.top();
        q.pop();
        sum+=tmp*tmp;
    }
    cout<<sum<<endl;
}

編劇真的就是腦洞開花了,導演也不管,那種東西都拍的出來,我真的是裂開!
在這裡插入圖片描述
溜了溜了~~

相關文章