给你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;
}