打印费用 Printer

34 篇文章 0 订阅
31 篇文章 0 订阅

【题意】如同一家正常的打印店一样,当打印的张数大于等于ai时每张打印件的费用为bi。保证ai递增,bi递减。
有m<=1e5个询问,问当打印张数为qi时,最小费用是多少。
【分析】最小费用应该是按张数打印,或者是额外打印一定张数以减小总体费用。关键在于应该额外打印多少张。
我们可以利用bi递减的这个性质。如果定义d=费用*限制张数,如果 d i &lt; = d i + 1 d_i &lt;= d_{i+1} di<=di+1、则在额外打印的情况下,i号方案一定不优于第i+1号方案,应该被排除。按张数打印时,如果张数在 s i s_i si s i + 1 s_{i+1} si+1之间,则打印 s i + 1 s_{i+1} si+1张一定比按张数打印优秀,也可以排除。

所以我们可以构建一个单调的序列,按di值单调递增。每次二分找小于等于qi和最小的ai的值。答案就是 q i ∗ d i q_i*d_i qidi a i + 1 ∗ b i + 1 a_{i+1}*b_{i+1} ai+1bi+1
【code】

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=1e5+1000;
struct node{
	LL s,p;
}a[maxn];
int n,m,cnt;
template<typename T> inline void read(T &x){
	x=0;T fl=1;char tmp=getchar();
	while(tmp<'0'||tmp>'9') {if(tmp=='-') fl=-fl;tmp=getchar();}
	while(tmp>='0'&&tmp<='9') x=(x<<1)+(x<<3)+tmp-'0',tmp=getchar();x*=fl;
}
inline int ub(LL x){
	int l=1,r=cnt,ans,mid;
	while(l<=r){
		mid=l+r>>1;
		if(a[mid].s<=x) ans=mid,l=mid+1;
		else r=mid-1;
	}
	return ans;
}
int main(){
	freopen("printer.in","r",stdin);
	freopen("printer.out","w",stdout);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		LL s,p;read(s),read(p);
		while(cnt>0&&a[cnt].s*a[cnt].p>=s*p) cnt--;
		a[++cnt].s=s,a[cnt].p=p;
	}
	for(int i=1;i<=m;i++){
		LL q,ans;int id;
		read(q),id=ub(q);
		if(id!=n) ans=a[id+1].p*a[id+1].s;
		else ans=1LL<<50;
		ans=min(ans,a[id].p*q);
		cout<<ans<<endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值