题目大意
Shintaro\text{Shintaro}Shintaro有nnn条龙,第iii条龙的力量值为xix_ixi。现在Shintaro\text{Shintaro}Shintaro想与这些龙交朋友。
Shintaro\text{Shintaro}Shintaro会使用以下两种魔法来平衡龙的力量值(使某些龙的力量值相等),以免与他交朋友的龙互相打架。
强化魔法:消耗aaa点mpmpmp,使某条龙的力量值增加111点。
弱化魔法:消耗bbb点mpmpmp,使某条龙的力量值降低111点。
在第iii次,Shintaro\text{Shintaro}Shintaro想与前iii条龙交朋友(1≤i≤n)(1\leq i\leq n)(1≤i≤n)。我们有很多种使用魔法的方案,使前iii条龙力量值相等。请你找到消耗mpmpmp点数最小的方案,并输出mpmpmp点数。
1≤n≤105,1≤a,b≤104,1≤xi≤1091\leq n\leq 10^5,1\leq a,b\leq 10^4,1\leq x_i\leq 10^91≤n≤105,1≤a,b≤104,1≤xi≤109
题解
我们考虑将每条龙的力量值取到何值时代价最小。
对于每一个i(1≤i≤n)i(1\leq i\leq n)i(1≤i≤n),将前iii条龙龙放在数轴上,取一个点xxx,设在xxx之前有kkk条龙,则在xxx之后有i−ki-ki−k条龙。那么,我们将xxx往右移一个单位,如果移动后xxx的左边和右边的龙的数量不变,则代价会增加ka−(i−k)bka-(i-k)bka−(i−k)b。当ka−(i−k)b<0ka-(i-k)b<0ka−(i−k)b<0时,显然将xxx往右移一个单位是最优的,我们可以一直右移xxx,直到xxx在第k+1k+1k+1条龙对应的点上,然后继续判断新的kkk是否满足ka−(i−k)b<0ka-(i-k)b<0ka−(i−k)b<0,再继续右移,直到不满足ka−(i−k)b<0ka-(i-k)b<0ka−(i−k)b<0,此时如果再右移肯定不优。
也就是说,我们要找到第一个kkk使得ka−(i−k)b≥0ka-(i-k)b\geq 0ka−(i−k)b≥0,即k≥iba+bk\geq\dfrac{ib}{a+b}k≥a+bib。因为kkk为整数,所以k=⌈iba+b⌉k=\lceil\dfrac{ib}{a+b}\rceilk=⌈a+bib⌉,那么取第kkk条龙的力量值为所有龙最终的力量值即可使代价最小(这里的第kkk条龙指数轴上从小到大的第kkk条龙)。
我们把龙的力量值离散化一下,然后用权值线段树维护前iii条龙的力量值,还要维护线段树上的每个节点对应的区间中有多少条龙。每次用上面的方法求出kkk,在线段树中求前iii条龙中第kkk小的龙的力量值,再求出其他龙的力量值变为第kkk小的龙的力量值的代价之和即可。
时间复杂度为O(nlogn)O(n\log n)O(nlogn)。
code
#include<bits/stdc++.h>
#define lc k<<1
#define rc k<<1|1
using namespace std;
const int N=100000;
int n,k,v[N+5],num[N+5],hv[4*N+5];
long long a,b,sum,all,ans,tr[4*N+5];
void ch(int k,int l,int r,int x){
if(l==r&&l==x){
++hv[k];
tr[k]+=num[x];
return;
}
int mid=l+r>>1;
if(x<=mid) ch(lc,l,mid,x);
else ch(rc,mid+1,r,x);
hv[k]=hv[lc]+hv[rc];
tr[k]=tr[lc]+tr[rc];
}
int gtnum(int k,int l,int r,int x){
if(l==r) return l;
int mid=l+r>>1;
if(x<=hv[lc]) return gtnum(lc,l,mid,x);
else return gtnum(rc,mid+1,r,x-hv[lc]);
}
void find(int k,int l,int r,int x,int y){
if(x>y) return;
if(l>=x&&r<=y){
all+=hv[k];
sum+=tr[k];
return;
}
int mid=l+r>>1;
if(x<=mid) find(lc,l,mid,x,y);
if(y>mid) find(rc,mid+1,r,x,y);
}
int main()
{
// freopen("c.in","r",stdin);
// freopen("c.out","w",stdout);
scanf("%d%lld%lld",&n,&a,&b);
for(int i=1;i<=n;i++){
scanf("%d",&v[i]);num[i]=v[i];
}
sort(num+1,num+n+1);
int gs=unique(num+1,num+n+1)-num-1;
for(int i=1;i<=n;i++){
v[i]=lower_bound(num+1,num+gs+1,v[i])-num;
}
for(int i=1;i<=n;i++){
ch(1,1,n,v[i]);
k=(i*b+a+b-1)/(a+b);
int tmp=gtnum(1,1,n,k);
sum=all=0;find(1,1,n,1,tmp-1);
ans=(1ll*all*num[tmp]-sum)*a;
sum=all=0;find(1,1,n,tmp+1,n);
ans+=(sum-1ll*all*num[tmp])*b;
printf("%lld\n",ans);
}
return 0;
}
文章讨论了Shintaro如何使用强化和弱化魔法平衡n条龙的力量值,以最小化操作魔法点数。通过将龙的力量值离散化并利用线段树数据结构,文章提出了一种高效算法解决此问题。
190

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



