版权声明:写得不好,随便转载,但请注明出处,感激不尽 https://blog.csdn.net/xyc1719/article/details/83416634
【题意】如同一家正常的打印店一样,当打印的张数大于等于ai时每张打印件的费用为bi。保证ai递增,bi递减。
有m<=1e5个询问,问当打印张数为qi时,最小费用是多少。
【分析】最小费用应该是按张数打印,或者是额外打印一定张数以减小总体费用。关键在于应该额外打印多少张。
我们可以利用bi递减的这个性质。如果定义d=费用*限制张数,如果
、则在额外打印的情况下,i号方案一定不优于第i+1号方案,应该被排除。按张数打印时,如果张数在
和
之间,则打印
张一定比按张数打印优秀,也可以排除。
所以我们可以构建一个单调的序列,按di值单调递增。每次二分找小于等于qi和最小的ai的值。答案就是
或
【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;
}