【题意】如同一家正常的打印店一样,当打印的张数大于等于ai时每张打印件的费用为bi。保证ai递增,bi递减。
有m<=1e5个询问,问当打印张数为qi时,最小费用是多少。
【分析】最小费用应该是按张数打印,或者是额外打印一定张数以减小总体费用。关键在于应该额外打印多少张。
我们可以利用bi递减的这个性质。如果定义d=费用*限制张数,如果
d
i
<
=
d
i
+
1
d_i <= 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
qi∗di或
a
i
+
1
∗
b
i
+
1
a_{i+1}*b_{i+1}
ai+1∗bi+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;
}