时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
给一个长度为n的数组a,现在要你构造一个长度为n的数组b,使得数组b的元素总和恰好为m且每个元素最小值不能小于0,且 最小,求出这个最小值
输入描述:
第一行输入两个数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;
}