打印费用 Printer

版权声明:写得不好,随便转载,但请注明出处,感激不尽 https://blog.csdn.net/xyc1719/article/details/83416634

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

所以我们可以构建一个单调的序列,按di值单调递增。每次二分找小于等于qi和最小的ai的值。答案就是 q i d i q_i*d_i a i + 1 b i + 1 a_{i+1}*b_{i+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;
}

猜你喜欢

转载自blog.csdn.net/xyc1719/article/details/83416634