专栏文章
题解 P9982
P9982题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @miqs9n5t
- 此快照首次捕获于
- 2025/12/04 09:54 3 个月前
- 此快照最后确认于
- 2025/12/04 09:54 3 个月前
题意:
给定一些点数轴上的整点 和 ,调整 并最小化下式:
思路:
不难观察到原式单谷,关键是怎么证。
考虑最优解的点,设其左侧有 个谷仓,右侧有 个谷仓,自身位置有 个谷仓。右移一个单位长度的贡献是 。左移一个单位长度的贡献是 。
显然,这两个值必然是正的。
考虑不断向左或向右移动,对于上述两个式子,每次经过谷仓后,第一项的系数会不断增加,第二项的系数会不断下降。即:贡献只会单调上升。
初始化每个位置左右的谷仓距离之和,对于每个点我们可以 计算该位置的分数。二分或三分找最低点即可。
复杂度 。
程序如下:
CPP#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=2e5+5,M=1e6+5;
long long n,q,a,b,x[N],pre[M],pos[M];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&x[i]),x[i]++;
sort(x+1,x+n+1);
int fr=0,cur=1;
for(int i=1;i<=x[n];i++){
pre[i]=pre[i-1]+fr;
while(x[cur]==i)cur++,fr++;
}
fr=0,cur=n;
for(int i=x[n];i>=1;i--){
pos[i]=pos[i+1]+fr;
while(x[cur]==i)cur--,fr++;
}
pre[0]=pre[x[n]+1]=1e9;
pos[0]=pos[x[n]+1]=1e9;
scanf("%d",&q);
while(q--){
scanf("%d%d",&a,&b);
long long l=1,r=x[n],ans;
while(l<r){
int mid=(l+r)>>1;
long long curans=pre[mid]*a+pos[mid]*b;
long long nxtans=pre[mid+1]*a+pos[mid+1]*b;
if(nxtans<curans)l=mid+1;
else r=mid;
}
printf("%lld\n",pre[l]*a+pos[l]*b);
}
return 0;
}
THE END
USACO 2024 Dec RP++.
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...