微信扫一扫打赏支持

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。

 

输出格式:

 

只有一个整数,表示最多可以选出的梨子个数。

 

输入输出样例

输入样例#1:
3
2 3 6
3 2
1 1
2 1
输出样例#1:
2

说明

各个测试点2s

样例说明:可以选择1、3两个梨子或者2、3两个梨子。

 

 

分析:

反正蒟蒻没推出dp式子,但是把不等式化一化,然后弄个排序暴力模拟均摊N^2的效率跑过去了。

简单的讲一件怎么搞吧。

首先根据题意:c1*(ai-a0)+c2*(bi-b0)<=c3

---->c1*ai+c2*bi-c3<=c1*a0+c2*b0

显然,不等式的左边是关于i的一个常数,弄个数组d先保存好。然后我们来看看怎么处理右边。

我们常规的思路就是:枚举a0,b0(n^2),然后再暴力统计一下(n),总的O(n^3),我们借鉴一下单调队列优化dp的思路,考虑直接枚举a0,但是把b0排序好,然后按某种方式统计,看看能否提高效率。

先从理论上分析是否有提高的可能性:首先d数组必须要排序,由于d数组的单调不下降性,所以b0枚举如果是有序的,那么是可以节省一些时间的!

再来仔细分析一下怎么来优化:我们先一层循环枚举a0,然后一层循环枚举b0,然后一层循环在d数组统计答案

显然,如果我们枚举到一个a0[i],b0[j],当枚举到d[k]时,不等式不成立了,那么另一句话就是从1...k-1不等式都是成立的,那么我们计算b0[j+1]的结果时,只有在原b数组中1....k-1中大于b0[j+1]的数字是不合法的,然后直接从k到n继续判断d[k]是否能使不等式成立就行了,

这时就是一个类似单调队列优化dp的过程了!

先给一段伪代码:

for i=1 to n

for j=1 to n

  for k=k to n

第三层循环的k是不下降的,所以最多只会在j的循环下枚举n次(均摊意义),所以总的就是O(n*n)的了!

那么如何维护一下1....k-1中大于某个数的数字个数呢?

想到逆序对没有?对呀,树状数组不就好了?

不过更巧妙的,由于我们这里有了一层循环,并且b0的枚举是有序的,我们直接开个桶,累计每个数字使用的次数,然后累加时把小于当前数字桶中的全减掉,然后把那个数字的桶清空,防止重复减就行了!

当然,想不到桶的做法也是没有关系的,毕竟n只有2000,用树状数组logn=11,那么就是2000*2000*11=4.4*10^7。还是可以过的哟

(^U^)ノ~YO

参考代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 const int N=2010;
 6 struct Pear{
 7     int v,idx;
 8     bool operator < (const Pear &rhs) const{
 9         return v<rhs.v;
10     }
11     Pear(int v=0,int idx=0):v(v),idx(idx){}
12 }c[N],d[N];
13 int a[N],b[N],sum[N];
14 int n,c1,c2,c3;
15 int main(){
16     scanf("%d%d%d%d",&n,&c1,&c2,&c3);
17     //c1*(ai-a0)+c2*(bi-b0)<=c3
18     //c1*ai+c2*bi-c3<=c1*a0+c2*b0
19     for (int i=1;i<=n;i++){
20         scanf("%d%d",&a[i],&b[i]);
21         c[i]=Pear(b[i],i);
22         d[i]=Pear(a[i]*c1+b[i]*c2-c3,i);
23     }
24     sort(c+1,c+n+1);sort(d+1,d+n+1);
25     int res=0;
26     for (int i=1,ans=0;i<=n;i++,ans=0){
27         memset(sum,0,sizeof(sum));
28         for (int j=1,k=0;j<=n;j++){
29             for (;k<=n && d[k].v<=c1*a[i]+c2*c[j].v;k++){
30                 if (a[d[k].idx]>=a[i] && b[d[k].idx]>=c[j].v){
31                     ans++;
32                     sum[b[d[k].idx]]++;
33                 }
34             }
35             ans-=sum[c[j-1].v];
36             sum[c[j-1].v]=0;
37             res=max(res,ans);
38         }
39     }
40     printf("%d",res);
41     return 0;
42 }

 

posted @ 2017-09-30 23:15  范仁义  阅读(535)  评论(0编辑  收藏  举报