CF960B Minimize the error
CF960B Minimize the error
题意翻译
有两个长度均为 nnn 的序列 a,ba,ba,b,定义 cost(a,b){\rm cost}(a,b)cost(a,b) :
cost(a,b)=∑i=1n(ai−bi)2{\rm cost}(a,b)=\sum_{i=1}{n}\left(a_{i}-b_{i}\right) cost(a,b)=i=1∑n(ai−bi)2
现在必须恰好对 aaa 进行 k1k_1k1 次操作,对 bbb 进行 k2k_2k2 次操作。操作内容是将某一项加一或者减一。求操作后的最小 cost\rm costcost。
translated by @皎月半洒花。
题解:
一道还不错的贪心。
发现首先应该考虑差最大的,然后等到把它消成第二大的之后再同时削第二大的...以此类推。
这个贪心的正确性可以证明,因为平方增长,先消差大的肯定不亏。
那么上面的消除过程就可以模拟来解决。
直接优先队列,非常方便。
需要注意的是,由于操作相同,对于两个数列的操作可以加一起。
代码:
#include <bits/stdc++.h>
using namespace std;
#define iter(i, a, b) for(int i=(a); i<(b); i++)
#define rep(i, a) iter(i, 0, a)
#define rep1(i, a) iter(i, 1, (a)+1)
#define fi first
#define se second
#define pb push_back
#define ll long long
#define pii pair<int, int>
const int MOD = 1e9+7;
int a[1003], b[1003];
priority_queue<int, vector<int>> pq;
signed main()
{
int n, k1, k2;
scanf("%lld%lld%lld",&n,&k1,&k2);
k1 += k2;
rep(i, n)
scanf("%lld",&a[i]);
rep(i, n)
{
scanf("%lld",&b[i]);
pq.push(abs(a[i]-b[i]));
}
while(k1--)
{
int t = pq.top();
pq.pop();
if(t == 0)
pq.push(1);
else
pq.push(t-1);
}
ll ans = 0;
while(!pq.empty())
{
ans = ans + 1ll * pq.top() * pq.top();
pq.pop();
}
cout << ans << endl;
return 0;
}