2019暑期集训第一次校赛-C 构造B数组
链接:https://ac.nowcoder.com/acm/contest/1068/C
来源:牛客网
题目描述
给一个长度为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
思路
要a[i] * (a[[i]-b[i]) * (a[[i]-b[i])的和最小,不妨令数组b的元素全为0,在尝试性对b的每元素加1,其差值越大则说明对这个b[i]加1对最后结果的贡献越忧,最后结果要求a[i] * (a[[i]-b[i]) * (a[[i]-b[i])的和最小。则每一轮尝试性给每个b加1,选出差值最大的给其b[i]加1,进行m轮此操作最后形成的b数组则能符合要求
题解
#include<iostream>
#include<queue>
using namespace std;
struct node
{
int a,b,cz;
bool operator < (const node& st)const{ //优先队列<号比出大小,默认大的值在顶部 ,值越大优先级就越大
return cz<st.cz; //sort函数<号比出大小,默认小的在前面
}
};
priority_queue<node> pt;
node st;
void zz(node st)
{
st.cz=st.a*(st.a-st.b)*(st.a-st.b)-st.a*(st.a-st.b-1)*(st.a-st.b-1);
pt.push(st);
return ;
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>st.a;
st.b=0;
zz(st);
}
for(int i=1;i<=m;i++)
{
st=pt.top();
pt.pop();
// cout<<st.a<<' '<<st.b<<' '<<st.cz<<endl;
st.b++;
zz(st);
}
long long sum=0;
for(int i=1;i<=n;i++)
{
if(!pt.empty())
{
st=pt.top();
pt.pop();
sum+=st.a*(st.a-st.b)*(st.a-st.b);
}
}
cout<<sum<<endl;
}