zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    条件转移指令小结
    《那些年啊,那些事——一个程序员的奋斗史》——50
    《那些年啊,那些事——一个程序员的奋斗史》——50
    《那些年啊,那些事——一个程序员的奋斗史》——51
    《那些年啊,那些事——一个程序员的奋斗史》——51
    《那些年啊,那些事——一个程序员的奋斗史》——52
    《那些年啊,那些事——一个程序员的奋斗史》——49
    《那些年啊,那些事——一个程序员的奋斗史》——51
    《那些年啊,那些事——一个程序员的奋斗史》——52
    《那些年啊,那些事——一个程序员的奋斗史》——50
  • 原文地址:https://www.cnblogs.com/Renyi-Fan/p/7616463.html
Copyright © 2011-2022 走看看