Description
给出n天内每天美元和英镑对一种特殊货币burles的汇率,有m件物品,每种物品只能用美元或者英镑买,一个人有s个burles,她不能存着美元或者英镑,只能在买东西的时候再兑换,且每种物品只能买一次,问这个人想买k件物品最少需要多少天
Input
第一行四个整数n,m,k,s分别表示天数,物品数,要买的物品数和钱数,之后n个整数a[i]表示第i天一美元值多少burles,再有n个整数b[i]表示第i天一英镑值多少burles,最后m行每行两个整数ti和ci表示第i种物品能用哪种货币买(1表示美元2表示英镑),ci表示买该物品的花费
(1<=n<=2e5,1<=k<=m<=2e5,1<=s<=1e9,1<=ai,bi<=1e6,1<=ci<=1e6)
Output
如果n天内可以买到k件物品则输出最少天数以及要买的k件物品编号以及买这件物品的时间,否则输出-1
Sample Input
5 4 2 2
1 2 3 2 1
3 2 1 2 3
1 1
2 1
1 2
2 2
Sample Output
3
1 1
2 3
Solution
预处理a和b序列的前缀最小值ma[i]和mb[i]表示要在汇率最小时买才能使得burles最有价值,把两种货币能买的物品分别按价值升序排后求一个前缀和sb[i]和sp[i]表示每次买最便宜的物品,二分天数,对于一个二分值mid,枚举买能够用第一种货币买的物品的数量x,那么用第二种货币要买k-x个物品,维护ma[mid]*sb[x]+mb[mid]*sp[k-x]的最小值,如果最小值不超过s说明二分值合法,缩小二分值找更优的解,否则二分值过小,移动区间左端点判更大的二分值是否合法
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 222222
int n,m,k,s,n1,n2,x;
int a[maxn],b[maxn],ma[maxn],mb[maxn];
struct node
{
int c,id;
bool operator<(const node&b)const
{
return c<b.c;
}
}d[maxn],p[maxn];
ll sd[maxn],sp[maxn];
bool check(int mid)
{
int aa=a[ma[mid]],bb=b[mb[mid]],t=-1;
for(int i=0;i<=k;i++)
if(i<=n1&&k-i<=n2)
{
if(t==-1||sd[i]*aa+sp[k-i]*bb<sd[t]*aa+sp[k-t]*bb)
t=i;
}
if(sd[t]*aa+sp[k-t]*bb<=s)
{
x=t;
return 1;
}
return 0;
}
int main()
{
while(~scanf("%d%d%d%d",&n,&m,&k,&s))
{
n1=n2=0;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)scanf("%d",&b[i]);
int temp=1;
for(int i=1;i<=n;i++)
if(a[i]>=a[temp])ma[i]=temp;
else ma[i]=temp=i;
temp=1;
for(int i=1;i<=n;i++)
if(b[i]>=b[temp])mb[i]=temp;
else mb[i]=temp=i;
for(int i=1;i<=m;i++)
{
int type,c;
scanf("%d%d",&type,&c);
if(type==1)d[++n1].c=c,d[n1].id=i;
else p[++n2].c=c,p[n2].id=i;
}
sort(d+1,d+n1+1),sort(p+1,p+n2+1);
sd[0]=sp[0]=0;
for(int i=1;i<=n1;i++)sd[i]=sd[i-1]+d[i].c;
for(int i=1;i<=n2;i++)sp[i]=sp[i-1]+p[i].c;
int l=1,r=n+1,mid,ans=n+1;
while(l<r)
{
mid=(l+r)/2;
if(check(mid))ans=mid,r=mid;
else l=mid+1;
}
if(ans==n+1)printf("-1\n");
else
{
printf("%d\n",ans);
for(int i=1;i<=x;i++)printf("%d %d\n",d[i].id,ma[ans]);
for(int i=1;i<=k-x;i++)printf("%d %d\n",p[i].id,mb[ans]);
}
}
return 0;
}