解题思路
首先,我们很容易想到这道题的贪心思想,把所有的商品按收益排序,从前往后对每件商品进行抉择,对于第i件商品,如果存在期限内的某天还没有售卖商品,就选择可售卖该商品的最后一天卖掉它,然后将该天设置为已售卖。流程:从该商品的期限日期向前枚举日期,一旦遇到没有售卖的日期,就找到了答案。这样的时间复杂度为 O ( N 2 ) O(N^2) O(N2)
考虑优化时间复杂度:
我们发现,瓶颈在于查找每个商品可以被卖的最后日期。我们可以将每个日期抽象为一个集合,集合的代表即为整个集合唯一没有售卖过商品的日期。不难发现,每个集合的代表一定是集合的日期中最小的。这些日期显然可以用并查集维护。
SO,查找每个商品可以被卖的最后日期的流程为:
找出商品过期时间所在的集合的代表元素,如果其集合代表元素不为 0 0 0,则在其代表元素那天卖掉该商品。并将这个集合并入那天的前一天(代表元素的前一天)所在的集合中。
代码
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<bitset>
using namespace std;
int n,p[10010],d[10010],fa[10010],maxn,ans;
struct c{
int p,d;
}a[10010];
bool cmp(c l,c r)
{
return l.p>r.p;
}
int find(int x)
{
if(fa[x]==x)return x;
else return fa[x]=find(fa[x]);
}
int main(){
while(scanf("%d",&n))
{
maxn=0,ans=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].p,&a[i].d);
maxn=max(maxn,a[i].d);
}
sort(a+1,a+n+1,cmp);//从大到小
for(int i=1;i<=maxn;i++)fa[i]=i;
for(int i=1;i<=n;i++)
{
int x=find(a[i].d);
if(x!=0)//看过期时间
{
ans+=a[i].p;
fa[x]=x-1;//并入代表元素的前一天
}
}
printf("%d\n",ans);
}
}