题解:[JOI 2026 二次预选] 购物 3 / Shopping 3

题目传送门

题意分析

询问之间独立,分开考虑 \(c,d\)

答案与 \(a_i\) 顺序无关,不妨令 \(a_1,a_2,\cdots,a_n\) 单调不降。

单次询问答案为:

\[\min_{k=0}^{\lceil\frac{a_n}{d}\rceil}\left(\sum_{i=1}^n\max(a_i-kd,0)+kc\right) \]

暴力做复杂度肯定是错的。

考虑抛开 \(\min\) 的限制,答案是一个函数:

\[\sum_{i=1}^n\max(a_i-kd,0)+kc \]

因为 \(\displaystyle\sum_{i=1}^n\max(a_i-kd,0)\)\(k\) 增加而单调不升,\(kc\)\(k\) 增加而单调不降。两个单调函数加到一起,可以得到一个单峰函数。

显然是一个凸函数,随 \(k\) 增加先单调不升再单调不降。

然后模拟赛时想到某 OI 书籍的一句话:

二分利用的是函数的单调性,三分利用的是函数的单峰性。

然后写了一个三分,挂了,被 JOI 绑包得到了 \(6\) 分的高分。

事实上三分的正确性不太能保证,因为可能会存在平台,然后就炸完了。

处理方法是三分到区间长度足够小的时候(例如 \(\leq10\)),暴力扫一遍求最小值。

AC 代码

//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
#include<random>
using namespace std;
typedef long long ll;
#define int ll
constexpr const int N=300000+1000,Q=300000+1000;
constexpr const ll inf=0x3f3f3f3f3f3f3f3f;
constexpr const double eps=1e-7;
mt19937 Rand(time(0));
int n,q,a[N+1],c[Q+1],d[Q+1];
ll pre[N+1];
ll calc(int j,int k){
	ll pl=pre[n]+k*(c[j]-(n+1ll)*d[j]);
	int p=upper_bound(a+1,a+n+1,1ll*k*d[j])-a;
	return pl+1ll*p*k*d[j]-pre[p-1];
}
main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	cin>>n>>q;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++){
		pre[i]=pre[i-1]+a[i];
	}
	for(int i=1;i<=q;i++){
		cin>>c[i]>>d[i];
	}
	for(int j=1;j<=q;j++){
		int l=0,r=(a[n]+d[j]-1)/d[j];
		int d=max(1ll,(r-l)>>2),k=l+r>>1;
		ll ans=min(pre[n],calc(j,k));
		while(d){
			int k1=max(l,k-d),k2=min(k+d,r);
			ll pl1=calc(j,k1),pl2=calc(j,k2),pl=calc(j,k);
			if(pl1<=pl2&&pl1<pl){
				k=k1;
				ans=min(ans,pl1);
			}else if(pl2<pl&&pl2<=pl1){
				k=k2;
				ans=min(ans,pl2);
			}else{
				d/=2;
			}
		}
		cout<<ans<<'\n';
	}
	
	cout.flush();
	
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}
/*
10 1
9628 862 6594 1995 5388 4401 3594 3580 3075 1880
11444 3009

26641
*/
posted @ 2026-07-09 16:18  TH911  阅读(2)  评论(0)    收藏  举报