正题
有 nnn 堆石子,第 iii 堆石子有 aia_iai个石头。你可以进行最多 mmm 次分裂操作,每次操作可以将一堆石子分为两堆(操作前后的石头数量总和保持不变)。你需要最小化每堆石子的数量的平方和。
很容易可以想到,每堆石子的价值和分裂次数的关系是凹性的。分的越多次,价值下降的越慢。
所以我们可以用一个堆来维护下一个要将那一堆石子进行分裂,堆中按照新分裂相比上一次减少的价值从大到小排序,每次取出一堆石子,将新的价值计入答案后,计算分裂多一次该堆石子产生的新贡献。
#include<bits/stdc++.h>
using namespace std;
const int N=50010;
int n,m,T,a[N];
struct node{
long long c;
int a,b;
bool operator<(const node q)const{
return c<q.c;
}
};
priority_queue<node> qs;
long long gs(int x,int t){
t=min(t,x);
return 1ll*x%t*(x/t+1)*(x/t+1)+1ll*(t-x%t)*(x/t)*(x/t);
}
int main(){
scanf("%d %d %d",&n,&m,&T);
while(T--){
while(!qs.empty()) qs.pop();
long long ans=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]),ans+=1ll*a[i]*a[i];
qs.push((node){1ll*a[i]*a[i]-gs(a[i],2),i,2});
}
int tmp=m;
while(tmp--){
node X=qs.top();qs.pop();
ans-=X.c;
X.b++;X.c=gs(a[X.a],X.b-1)-gs(a[X.a],X.b);
qs.push(X);
}
printf("%lld\n",ans);
}
}
本文介绍了一种解决石子分裂问题的算法,通过利用凹性性质和优先队列,最小化每堆石子数量的平方和。在每次分裂操作中,根据新分裂带来的价值减少进行排序,从而高效地确定分裂策略。代码示例展示了如何实现这一算法,最终输出最小的平方和。

被折叠的 条评论
为什么被折叠?



