时间限制:C/C++ 1秒,其他语言2秒

空间限制:C/C++ 262144K,其他语言524288K

64bit IO Format: %lld

题目描述

给一个长度为n的数组a,现在要你构造一个长度为n的数组b,使得数组b的元素总和恰好为m且每个元素最小值不能小于0,且 构造B数组(优先队列)_数组 最小,求出这个最小值

输入描述:

第一行输入两个数n,m (1 <= n, m <= 1e5)

第二行输入n个数表示ai(1 <= ai <= 1e3)

输出描述:

一个数,表示答案

示例1

输入

复制

3 1
1 2 3

输出

复制

21

示例2

输入

复制

3 5
1 1 2

输出

复制

1

【题解】

将bi看成x,那么令f(x)=ai(ai-x)(ai-x),对f(x)求导,发现导函数为递增函数。则每次把f(x+1)-f(x)的值放入优先队列,递增小的优先,x为当前分配量。类似差分贪心

由于x必须大于等于0,所以所有的x初始值为0

【代码】

/*
神仙做法
*/
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 1e5+10;

struct Node
{
int a;
int x;
ll sum, sub;
bool operator < (const Node& that) const
{
return this->sub > that.sub;
}
void Update()
{
sum = a*(a-x)*(a-x);
sub = a*(a-x-1)*(a-x-1)-sum;
}
Node(int aa,int xx):a(aa),x(xx){}
};
int n, m;

int main()
{
scanf("%d %d", &n, &m);
int a, b, c;
priority_queue<Node> que;
for (int i = 1;i <= n;i++)
{
scanf("%d",&a);
Node node(a,0);
node.Update();
que.push(node);
}
ll res = 0;
while (m--)
{
Node now = que.top();
que.pop();
now.x++;
now.Update();
que.push(now);
}
while (!que.empty())
{
res += que.top().sum;
que.pop();
}
printf("%lld\n", res);

return 0;
}