CF1928D Lonely Mountain Dungeons 题解

CF1928D Lonely Mountain Dungeons

提供一个三分做法。

假设我们已经知道了分 x 队,那对于每一个种族,我们就应该尽量平均分到这 x 个队伍中。我们可以先将总数 ci 平均分,再把余数 r 分给前 r 个元素,每个元素分一个 1

然后,我们需要统计答案。我们发现这是一个类似带权数线段的计数,所以我们对于平均分之后的数维护一个后缀和。每处理到一个数时,将后缀和减去这个数,并用这个数乘以后缀和乘以 b 累加到答案中。这个过程的时间复杂度是 O(ci) 的,由于题目保证 ci2×105,这个时间复杂度可以接受。

接下来,我们考虑优化寻找答案的过程。记分 x 队的战斗力为 Fx,可以证明 Fx 为单峰函数。当前分的队数越多,扩一个队能增加的收益就越少。因为同一个队不可以贡献的对数是该队人数平方级别的,分的队数越多,平均分人数减少越慢。但是扩一个队的代价一定,所以答案的差分是递减的。因此,Fx 为单峰函数。

既然答案是单峰的,直接三分即可。

#include <bits/stdc++.h>
using namespace std;
long long t,n,b,x,a[300000];
long long check(long long w)
{
	long long ans=0;
	if(w==0)return 0;
	for(int i=1;i<=n;i++)
	    {
	    	long long tol=a[i],s=a[i]/w,r=a[i]%w;
	    	for(int i=1;i<=r;i++)tol-=(s+1),ans+=(s+1)*tol;
	    	while(tol>0)tol-=s,ans+=s*tol;
		}
	return ans*b-x*(w-1);
}
 
int main()
{
	scanf("%lld",&t);
	while(t--)
	   {
	   	long long ans=0,mx=0;
	   	scanf("%lld%lld%lld",&n,&b,&x);
	   	for(int i=1;i<=n;i++)
	   	    {
		    scanf("%lld",&a[i]);
		    mx=max(mx,a[i]);
		    }
		long long l=0,r=mx;
		while(l<=r)
		   {
		   	long long mid1=(l*2+r)/3,mid2=(l+r*2)/3;
		   	if(check(mid1)<=check(mid2))ans=max(ans,check(mid2)),l=mid1+1;
		   	else r=mid2-1;
		   }
	   	printf("%lld\n",ans);
	   }
	return 0;
}

感谢 sunrise1024 提供的证明。

posted @   w9095  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示