新加坡动物园里有一些兔子。为了喂养它们,动物园管理员买了n根长度为a1, a2, a3,, an的胡萝卜。然而,兔子繁殖能力很强,繁殖速度很快。动物园管理员现在有k只兔子,没有足够的胡萝卜来喂养它们。为了解决这个问题,动物园管理员决定把胡萝卜切成k块。由于某种原因,所有得到的胡萝卜长度都必须是正整数。大胡萝卜对兔子来说很难处理和吃,所以吃一根z大小的胡萝卜所需的时间是z2。帮助动物园管理员把胡萝卜分开,同时尽量减少兔子吃胡萝卜的时间。输入第一行包含两个整数n和k (1 <n <k < 105):胡萝卜的初始数量和兔子的数量。下一行包含n个整数a1, a2,,an (1 < a < 10):胡萝卜的长度。它保证了a的总和;至少是k。输出输出一个整数:兔子吃胡萝卜所需的最小时间总和。
Examples
input
Copy
3 6 5 3 1
output
Copy
15
input
Copy
1 4 19
output
Copy
91
请注意对于第一个测试,胡萝卜的最佳大小是{1,1,1,2,2,2}。所花费的时间为12 +12 +12 +22 +22 +22 = 15对于第二次测试,胡萝卜的最佳大小为{4,5,5,5}。所用时间为42 +52 +52 +52 = 91。
题解:
一开始的思路是,优先队列,数存进去,每次取出最大的,然后最大平均分成两份,再存进去,直到有k份
但这样是不行的,明显的一个hack样例就是
1 3
6
按我们写的是1 2 3
正确应该是2 2 2
我们首先把当前1~n每个萝卜分成1和1 + 1份
得到相减的结果
get(a[i],1) - get(a[i],1 + 1)
每根萝卜的最优解就是均分,那么有个大胆的想法就是将每个萝卜的当前最小花费和多分一段的最小花费的差值放进大根堆里面,然后执行k-n次,每次就减去最大值,不得不说太优秀了这个想法。(一种很好的思想)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
#define int long long
struct node
{
int a,b,c;
friend bool operator < (const node &a,const node&b)
{
return a.a < b.a;
}
};
int get(int x,int y)
{
int a = x/y;
int b = x%y;
return a*a*(y - b) + (a + 1)*(a + 1)*b;
}
void solve()
{
int n,k;
cin >> n >> k;
int ans = 0;
priority_queue <node> q;
for(int i = 1;i <= n;i++)
{
int x;
cin >> x;
ans += x*x;
q.push({get(x,1) - get(x,2),2,x});
}
int p = k - n;
for(int i = 1;i <= p;i++)
{
node t = q.top();
q.pop();
int a = t.a;
int b = t.b;
int c = t.c;
ans -= a;
q.push({get(c,b) - get(c,b + 1),b + 1,c});
}
cout << ans;
}
signed main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);cout.tie(0);
int t = 1;
// cin >> t;
while(t--)
{
solve();
}
}