7-144 Shopping With Coupons
题意
\(n\) 个商品,第 \(i\) 个商品价格为 \(a_i\),\(n\) 种优惠券,第 \(j\) 种优惠券优惠金额为 \(b_j\)。
你现在有 \(D\) 元钱,询问你可以选择的最多的两两不同的二元组 \((i,j)\) 使得 \((\sum (a_i-b_j))\le D\)。
解题报告
首先每个物品如果要买,一定是从优惠金额最大的优惠券开始用。
那么直接维护一个堆维护每个物品 当前的最小花费,然后贪心选取即可。
然后不知道怎么回事,至少我没看到题面里有写,这题作者比较憨憨,他似乎规定买东西一定要用优惠卷买,哪怕当前有一个原价价格更低的物品,他也要用优惠券买一个减价之后更贵的物品。
所以这是个社会现象分析题。
我的处理方法是新添一张优惠金额为 -inf 的优惠券,使得这种情况得到避免。
因为有物品价格 \(>\) 优惠券金额,所以复杂度最大为 \(\operatorname O(D\log n)\)。
Code
#include <stdio.h>
#include <algorithm>
#define LL long long
using namespace std;
const int Rea=1e5+3;
struct Rin
{
char c;
inline char gc()
{
static char rea[Rea];
static char *head,*tail;
return head==tail&&(tail=(head=rea)+fread(rea,1,Rea,stdin),head==tail)?EOF:*head++;
}
inline Rin&operator >>(int &x)
{
x=0;
bool tag=false;
for(c=gc();c>'9'||c<'0';c=gc())if(c=='-'){c=gc();tag=true;break;}
for(;c>='0'&&c<='9';c=gc())x=(x<<1)+(x<<3)+(c^'0');
if(tag)x=-x;
return *this;
}
}rin;
inline void jh(int &x,int &y){if(x^y)x^=y^=x^=y;return;}
const int N=1e6+3;
int n,m;
int ans;
int a[N];
int b[N];
int c[N];
int d[N];
int tail;
inline int v(int x){return a[x]-b[c[x]];}
inline void up(int x){if(x==1)return;if(v(d[x])<v(d[x>>1]))jh(d[x],d[x>>1]),up(x>>1);}
inline void down(int x)
{
if((x<<1)>tail)return;
int nxt=x;if(v(d[x<<1])<v(d[nxt]))nxt=x<<1;if(((x<<1)|1)<=tail&&v(d[(x<<1)|1])<v(d[nxt]))nxt=(x<<1)|1;
if(nxt!=x)jh(d[x],d[nxt]),down(nxt);return;
}
inline void push(int x){d[++tail]=x;up(tail);return;}
inline int top(){return d[1];}
inline bool myru_b(int x,int y){return x>y;}
int main()
{
rin>>n>>m;
for(int i=1;i<=n;i++)rin>>a[i];
for(int i=1;i<=n;i++)rin>>b[i];sort(b+1,b+n+1,myru_b);b[n+1]=-0x3f3f3f3f;
for(int i=1;i<=n;i++)c[i]=1,push(i);
for(;true;ans++){int now=top();if(v(now)>m)break;m-=v(now);c[now]++;down(1);}
printf("%d %d\n",ans,m);
return 0;
}
\[\texttt{El Psy Congroo}
\]
$$\texttt{Dirty Deeds Done Dirt Cheap}$$

浙公网安备 33010602011771号