对于这题笔者无解,只有手抄一份正解过来了:
基本思想就是 :
- 二分答案,对于第x天,计算它最少的花费f(x),<=s就是可行的,这是一个单调的函数,所以可以二分。
- 对于f(x)的计算,我用了nlog(n)的算法,遍历m个商品,用c[i]乘以前x天里,第t[i]种货币的最便宜的价格,存放到一个数组里,之后排序,计算前k个的和就是f(x)
- 前x天里,第t[i]种货币的最便宜的价格是通过预处理得到的,很容易的计算一下前缀最小值就行了。
贴代码吧:
#include <iostream> #include <cstring> #include <cmath> #include <cstdio> #include <algorithm> using namespace std; typedef long long ll; typedef pair<ll,int> pii; #define fi first #define se second #define mp make_pair const int maxn = 200005; int a[maxn],b[maxn],t[maxn],c[maxn]; int n,m,k,s; int am[maxn],bm[maxn]; int ida[maxn],idb[maxn]; const int inf = 0x3f3f3f3f; pii pli[maxn]; int id[maxn]; ll f(int x){ ll ret = 0; for (int i=1;i<=m;i++){ if (t[i] == 1){ pli[i].fi = (ll)c[i] * (ll)am[x]; } else{ pli[i].fi = (ll)c[i] * (ll)bm[x]; } pli[i].se = i; } sort(pli+1,pli+m+1); for (int i=1;i<=k;i++){ ret += pli[i].fi; } return ret; } int main(){ cin>>n>>m>>k>>s; am[0] = bm[0] = inf; for (int i=1;i<=n;i++){ scanf("%d",&a[i]); if (a[i] < am[i-1]){ am[i] = a[i]; ida[i] = i; } else{ am[i] = am[i-1]; ida[i] = ida[i-1]; } } for (int i=1;i<=n;i++){ scanf("%d",&b[i]); if (b[i] < bm[i-1]){ bm[i] = b[i]; idb[i] = i; } else{ bm[i] = bm[i-1]; idb[i] = idb[i-1]; } } for (int i=1;i<=m;i++){ scanf("%d%d",&t[i],&c[i]); } ll low,high,mid; low = 1,high = n; ll d = -1; while(low <= high){ mid = (low + high) / (ll)2; if (f(mid) <= s){ high = mid - 1; d = mid; for (int i=1;i<=k;i++){ id[i] = pli[i].se; } } else{ low = mid + 1; } } cout << d <<"\n"; if (d == (ll)-1) return 0; int x = (int)d; for (int i=1;i<=k;i++){ printf("%d %d\n",id[i],t[id[i]]==1?ida[x]:idb[x]); } return 0; }
时间: 2024-10-14 14:39:03