P1493 分梨子
作者:互联网
P1493 分梨子
题目描述
Finley家的院子里有棵梨树,最近收获了许多梨子。于是,Finley决定挑出一些梨子,分给幼稚园的宝宝们。可是梨子大小味道都不太一样,一定要尽量挑选那些差不多的梨子分给孩子们,那些分到小梨子的宝宝才不会哭闹。
每个梨子都具有两个属性值,Ai和Bi,本别表示梨子的大小和甜度情况。假设在选出的梨子中,两个属性的最小值分别是A0和B0。只要对于所有被选出的梨子i,都满足C1*(Ai-A0)+C2*(Bi-B0)≤C3(其中,C1、C2和C3都是已知的常数),就可以认为这些梨子是相差不多的,可以用来分给小朋友们。
那么,作为幼稚园园长的你,能算出最多可以挑选出多少个梨子吗?
输入格式
第一行一个整数N(1≤N≤2000),表示梨子的总个数。
第二行三个正整数,依次为C1,C2和C3(C1,C2≤2000,C3≤10^9)。
接下来的N行,每行两个整数。第i行的两个整数依次为Ai和Bi。
输出格式
只有一个整数,表示最多可以选出的梨子个数。
输入输出样例
输入 #13 2 3 6输出 #1
3 2 1 1 2 1
2
说明/提示
各个测试点2s
样例说明:可以选择1、3两个梨子或者2、3两个梨子。
思路:由题目中的比较对象是选出的梨子里面最小的a和b,并且计算出来的值显然是具有单调性的,所以我们可以枚举所有的a以及所有的b,并且统计满足当下情况的个数,但是显然时间复杂度并不允许我们的n三次方的做法。但是根据题目中的单调性我们可以对计算出的值以及b进行从小到大的排序这样在内层检验是否合法时就不需要从头再枚举检验点,我们可以继承从小的b值转化过来的k,所以我们将范围扩展到整个i上面去,枚举所有可能的a0,b0计算每个满足每个a0,b0的值,发现此时需要维护的便是在1~k中小于某个数的个数,可以想到逆序对的做法,但是这里其实还有一种桶的做法,累计每个数字使用的次数,然后累加时把小于当前数字桶中的全减掉,然后把那个数字的桶清空,防止重复减就行了。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e3+5;
const int inf=0x3f3f3f3f;
struct hp
{
int id,val;
}an[maxn],p[maxn];
int sum[maxn];
int a[maxn],b[maxn];
bool cmp(hp a,hp b)
{return a.val<b.val;}
int main()
{
int n,c1,c2,c3;
scanf("%d %d %d %d",&n,&c1,&c2,&c3);
for(int i=1;i<=n;i++)
{
scanf("%d %d",&a[i],&b[i]);
p[i].id=i;
p[i].val=b[i];
an[i].id=i;
an[i].val=(c1*a[i]+c2*b[i]-c3);
}
an[n+1].val=inf;
sort(an+1,an+1+n,cmp);
sort(p+1,p+1+n,cmp);
int ans=0,tot=0;
for(int i=1;i<=n;i++)
{
memset(sum,0,sizeof(sum));
ans=0;
for(int j=1,k=0;j<=n;j++)
{
for(;(an[k].val<=(c1*a[i]+c2*p[j].val))&&k<=n;k++)
{
if(a[an[k].id]>=a[i]&&b[an[k].id]>=p[j].val)
{
sum[b[an[k].id]]++;//标记当前数字的使用次数
ans++;
}
}
ans-=sum[p[j-1].val];将小于当前数字值的桶清空,保证放入的梨子是选出来的最小的梨子
sum[p[j-1].val]=0;
tot=max(ans,tot); //记录的情况是以i为单位的
}
}
printf("%d\n",tot);
return 0;
}
标签:P1493,val,int,梨子,maxn,sum,id 来源: https://www.cnblogs.com/oiqwq/p/15303518.html