我不會貪心。
\(a\) 元的物品有 \(b\) 元的折扣,就相當於 \(a\) 元的物品有一張 \(a-b\) 元的優惠券。
因為一張優惠券是滿 \(w\) 元才可以用,所以可以用的物品在價格 \(a\) 上是一段區間 \([a,\inf]\)。
有一個很樸素的想法是,將每一個物品最多能省多少錢先弄出來,然後用優惠券想辦法把省的最小的錢換成優惠券。
先將物品和優惠券按滿多少可以有優惠排序,再列舉優惠券,最後就是按照上面說的逐步加進去就好了。
想要快速求出最小值可以用優先佇列,如果到最後還用不到優惠券的記得把打得折加進去。
時間複雜度 \(O(n \log n)\)。
點選檢視程式碼
#include<bits/stdc++.h>
#define int ll
#define mem(a,b) memset((a),(b),sizeof(a))
#define m0(a) memset((a),0,sizeof(a))
#define lb(x) ((x)&-(x))
#define lc(x) ((x)<<1)
#define rc(x) (((x)<<1)|1)
#define pb(G,x) (G).push_back((x))
#define For(a,b,c) for(int a=(b);a<=(c);a++)
#define Rep(a,b,c) for(int a=(b);a>=(c);a--)
#define in1(a) a=read()
#define in2(a,b) a=read(), b=read()
#define in3(a,b,c) a=read(), b=read(), c=read()
#define inn(i,n,a) For(i,1,n) a[i]=read();
#define ll long long
#define i128 __int128
using namespace std;
inline int read() {
int xx= 0;int f= 1;
char c = getchar();
while(c<'0'||c>'9') {
if(c=='-') f= -1;
c= getchar();
}
while(c>='0'&&c<='9') {
xx= (xx<<1)+(xx<<3)+(c^48);
c= getchar();
}
return xx*f;
}
#define maxn 1000050
int n,m;
struct node {
int x,y;
}a[maxn],b[maxn];
bool cmp(node a,node b) {
return a.x==b.x?a.y>b.y:a.x>b.x;
}
int res=0;
signed main() {
in2(n,m);
For(i,1,n) {
int x,y;
in2(x,y);
a[i].x=x,a[i].y=x-y;
res+=a[i].x;
}
For(i,1,m) {
in2(b[i].x,b[i].y);
}
int i=1;
sort(a+1,a+n+1,cmp);
sort(b+1,b+m+1,cmp);
priority_queue<int,vector<int>,greater<int> > q;
For(j,1,m){
while(i<=n&&a[i].x>=b[j].x) q.push(a[i].y),i++;
if(q.size()&&q.top()<b[j].y) {
q.pop();
q.push(b[j].y);
}
}
while(i<=n) q.push(a[i].y),i++;
while(q.size()) res-=q.top(),q.pop();
cout<<res;
}