codeforces(E. Carrots for Rabbits)贪心

题目链接

给你n个数,每个数再被切分若干份(整数),比如5可以切分为2、3或2、2、1等
通过切割将n个数变成k个数,使这k个数的平方和最小。

一开始是想将所有数放在一个优先队列里,每次取出最大的一分为二,但这样是不行的。
一个数切分后要想平方和最小,肯定要均分,设一个数当前的减少量为now,增加一次切分次数后的减少量为next,用一个堆维护next-now即可。(比如10的平方和为100,切分一次后的平方和为50,减少量为50)

代码:

//#pragma GCC optimize("Ofast")
//#pragma GCC target("avx,avx2,fma")
//#pragma GCC optimization ("unroll-loops")
#include <bits/stdc++.h>
#define pb push_back
#define ll long long
#define IOS std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
inline int read() {
    
    
    char c = getchar(); int x = 0, f = 1;
    while (c < '0' || c > '9') {
    
    if (c == '-')f = -1; c = getchar();}
    while (c >= '0' && c <= '9') {
    
    x = x * 10 + c - '0'; c = getchar();}
    return x * f;
}
using namespace std;

ll n,k,ans;
ll a[100005];
struct node
{
    
    
    ll num,aa,now,next;
    ll val;
};
struct CMP
{
    
    
    bool operator()(const node &e1,const node &e2)
    {
    
    
        return e1.val<e2.val;
    }
};
priority_queue<node,vector<node>,CMP> q;
ll query(ll all,ll x)
{
    
    
    if(all%x==0){
    
    return (all/x)*(all/x)*x;}
    ll s=0;
    s+=(all/x)*(all/x)*(x-all%x);
    s+=(all/x+1)*(all/x+1)*(all%x);
    return s;
}
int main()
{
    
    
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
    
    
        cin>>a[i];
        ans+=a[i]*a[i];
    }
    for(int i=1;i<=n;i++)
    {
    
    
        node e;
        e.aa=a[i];
        e.num=2;
        e.now=0;
        e.next=e.aa*e.aa-query(e.aa,e.num);
        e.val=e.next-e.now;
        q.push(e);
    }
    for(int i=1;i<=k-n;i++)
    {
    
    
        node e=q.top();
        q.pop();
        ans-=e.val;
        e.now=e.next;
        e.num++;
        e.next=e.aa*e.aa-query(e.aa,e.num);
        e.val=e.next-e.now;
        q.push(e);
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43781431/article/details/112567377