zoukankan      html  css  js  c++  java
  • LuoguP1314 聪明的质检员 【二分答案/前缀和】

    美丽的题号预示着什么...

    描述

    小 T 是一名质量监督员,最近负责检验一批矿产的质量。这批矿产共有n个矿石,从1到n逐一编号,每个矿石都有自己的重量wi以及价值vi。检验矿产的流程是:
    1、给定m个区间[Li,Ri];
    2、选出一个参数W;
    3、对于一个区间[Li,Ri],计算矿石在这个区间上的 检验值Yi

    这批矿产的 检验结果Y 为各个区间的检验值之和 。即: Y1+Y2...+Ym
    若这批矿产的 检验结果 与所给标准值S相差太多,就需要再去检验另一批矿产。小T不想费时间去检验另一批矿产,所以他想通过调整参数W的值,让 检验结果 尽可能的靠近标准值S,即使得 S-Y 的绝对值最小。请你帮忙求出这个最小值。

    格式

    输入格式

    第一行包含三个整数n,m,S,分别表示矿石的个数、区间的个数和标准值。

    接下来的n行,每行2个整数,中间用空格隔开,第i+1行表示i号矿石的重量wi和价值vi 。

    接下来的m行,表示区间,每行2个整数,中间用空格隔开,第i+n+1行表示区间[Li,Ri]的两个端点Li和Ri。 注意:不同区间可能重合或相互重叠。

    输出格式

    输出只有一行,包含一个整数,表示所求的最小值。

    样例1

    样例输入1

    5 3 15
    1 5
    2 5
    3 5
    4 5
    5 5
    1 5
    2 4
    3 3

    样例输出1

    10
    

    提示

    样例说明:当W选4的时候,三个区间上检验值分别为20、5、0,这批矿产的检验结果为25,此时与标准值S相差最小为10。

    对于10%的数据,有1 ≤ n,m ≤ 10;
    对于30%的数据,有1 ≤ n,m ≤ 500;
    对于50%的数据,有1 ≤ n,m ≤ 5,000;
    对于70%的数据,有1 ≤ n,m ≤ 10,000;
    对于100%的数据,有1 ≤ n,m ≤ 200,000,0 < wi, vi ≤ 10^6,0 < S ≤ 10^12,1 ≤ Li ≤ Ri ≤ n。

    来源

    NOIp2011提高组Day2第二题

    这道题...题面读了好久(晦涩难懂

    做背包做惯了于是以下及我的代码把数组v与w的意义调换了一下(v为重量,w为价值)

    因为参数值W是不固定的,而且坐落在有序的一段区间上(1~max v[i] ),所以我们可以愉快地使用二分答案。

    如果我们二分出的这个参数值使得Y较小,说明参数取得有些大,满足的值很少,我们向左移一移。

    如果我们二分出的这个参数值使得Y较大,说明参数取得有些小,满足的值很多,我们向右移一移。

    根据lyd老师的指引,我们愉快地写出了二分答案的代码

        int l=1,r=mx;
        while(l<r)
        {
            int mid=(l+r+1)>>1;
            Y=check(mid);
            if(Y<s) r=mid-1;
            else l=mid;
            ans=min(ans,abs(s-Y));
        }

    接下来就是check函数的写法。

    由于数据达到了1e6,我们肯定不能暴力计算区间和,前缀和坠吼了。

    ll check(int x)
    {
        ll tmp=0;
        for(int i=1;i<=n;i++)
        {
            sum[i]=sum[i-1];
            cnt[i]=cnt[i-1];
            if(v[i]>=x)
            {
                sum[i]+=w[i];
                cnt[i]++;
            }
        }
        for(int i=1;i<=m;i++)
         tmp+=(sum[q[i].second]-sum[q[i].first-1])*(cnt[q[i].second]-cnt[q[i].first-1]);
        return tmp;
    }

    于是我们就愉快地AC了。

    code

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<utility>
     4 #define inf (1LL<<60)
     5 
     6 using namespace std;
     7 typedef long long ll;
     8 
     9 int n,m,mx;
    10 int v[200009],w[200009];
    11 ll ans=inf,s,Y,sum[200009],cnt[200009];
    12 pair<int,int> q[200009];
    13 /*ll check(int x)
    14 {
    15     ll tmp=0;
    16     for(int i=1;i<=m;i++)
    17     {
    18         int pos=lower_bound(v+1,v+n+1,x)-v;
    19         if(pos>q[i].second) continue;
    20         int cnt=max(pos,q[i].first);
    21         tmp+=(w[q[i].second]-w[cnt-1])*(q[i].second-cnt+1);
    22     } 
    23     return tmp;
    24 }*/
    25 ll check(int x)
    26 {
    27     ll tmp=0;
    28     for(int i=1;i<=n;i++)
    29     {
    30         sum[i]=sum[i-1];
    31         cnt[i]=cnt[i-1];
    32         if(v[i]>=x)
    33         {
    34             sum[i]+=w[i];
    35             cnt[i]++;
    36         }
    37     }
    38     for(int i=1;i<=m;i++)
    39      tmp+=(sum[q[i].second]-sum[q[i].first-1])*(cnt[q[i].second]-cnt[q[i].first-1]);
    40     return tmp;
    41 }
    42 int main()
    43 {
    44     scanf("%d%d%lld",&n,&m,&s);
    45     for(int i=1;i<=n;i++)
    46      scanf("%d%d",&v[i],&w[i]),mx=max(mx,v[i]);
    47     for(int i=1;i<=m;i++)
    48      scanf("%d%d",&q[i].first,&q[i].second);
    49 /*    sort(a+1,a+n+1,cmp);*/
    50 /*    sum[1]=a[1].w;
    51     for(int i=2;i<=n;i++)
    52      sum[i]=sum[i-1]+a[i].w;*/
    53     
    54     int l=1,r=mx;
    55     while(l<r)
    56     {
    57         int mid=(l+r+1)>>1;
    58         Y=check(mid);
    59         if(Y<s) r=mid-1;
    60         else l=mid;
    61         ans=min(ans,abs(s-Y));
    62     }
    63     printf("%lld",ans);
    64     return 0;
    65 }
    View Code

    几个注意事项

    § 虽说没有负数的情况,但是ans初值本身开始也要赋得很大,否则会输出0. (因为这调了很久qaq),ans是long long类型,怎么赋初值?hzwer大神给了一个不错的写法

    #define inf (1LL<<60)

    § 开始想排一遍序,然后前缀和直接调用就好了。然而...并没有注意到还有区间下标的限制,还是老实做吧orz!

  • 相关阅读:
    P2P理财友情提示
    P2P理财友情提示
    如何在Chrome development tool里查看C4C前台发送的请求细节
    CRM和ERP的Sales Organization的映射关系
    如何从ERP将Material的Batch信息下载到CRM并存储在settype COMM_PR_BATCH里
    CRM中间件里的发布-订阅者模式
    CRM订单状态的Open, In process和Completed这些条目是从哪里来的
    如何证明CRM WebClient UI上的应用是有状态(Stateful)的
    如何使用代码获得一个function module的Where Used List
    观察者模式在One Order回调函数中的应用
  • 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9329702.html
Copyright © 2011-2022 走看看