zoukankan      html  css  js  c++  java
  • [NOIP2011]聪明的质检员

    // 此博文为迁移而来,写于2015年7月14日,不代表本人现在的观点与看法。原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w6ft.html

    1、题目



    2、TAG

           NOIP提高组;二分答案;前缀和。

     

    3、分析
           首先题面一定要看懂,看清(上次我就是没有看懂)。说白了,就是使W取一个最合适的值,使每一个所给区间内满足条件的矿石的数量乘上价值之和,最后计算总和使与S最近。
           我们根据分值分布来分析算法:
           1、30分算法:O(n^3),首先O(n)进行W值选取的枚举,然后O(n^2)判断+计算;
           2、50分算法:O(n^2 log n)。根据每次选取W值我们易发现,所得的总值是一个单调函数,随W增大而减小,且一定存在零点。故为了求得最小值,我们需要得到零点位于那两个整数之间。这样用二分显然比枚举快。O(log n)的二分加上O(n^2)的判断+计算;
           3、100分算法:200000的数据显然只能O(n log n)或者O(n)了,但是这道题O(n)很明显不现实。我们的任务在于,如何消去O(n^2)这么大的判断与计算?这里,可以采取前缀和优化——由于每次计算检验值之和的时候,W值固定,故可以用O(n)的时间扫描一遍用a[i]表示前i个矿石满足条件的个数;b[i]表示前i个满足条件的矿石价值之和。故每次询问一个区间的时候可以O(1)直接相减!这样,复杂度就降到了O(n log n)。(这其实是一个很简单的优化但是我想了很久,看来姿势不够)
           4、(这个可以无视)70分算法:存在这个分数段就必然存在这种算法对吧。。。这一定是给那些用了前缀和却没有用二分的。。。虽然我觉得很不可思议。
           还有一个很重要的数据范围——权值会爆INT。
     
    4、代码
    -----------------------------------------------------------------------------------------------------------------
    #include<cstdio>
    #include<cstring>
    #define MAXN 200005
    #define INF 1ll<<60
    typedef long long ll;
     
    ll max(ll a,ll b) { return (a>b)?a:b; }
    ll min(ll a,ll b) { return (a<b)?a:b; }
    ll abs(ll a) { return (a<0)?-a:a; }
     
    ll n,m,w[MAXN],v[MAXN],l[MAXN],r[MAXN],maxw,nl,nr;
    ll s,ans=INF,s1[MAXN],s2[MAXN];
     
    void init()
    {
            scanf("%lld %lld %lld",&n,&m,&s);
            for (int i=1;i<=n;i++) { scanf("%lld %lld",&w[i],&v[i]); maxw=max(maxw,w[i]); }
            for (int i=1;i<=m;i++) scanf("%lld %lld",&l[i],&r[i]);
    }
     
    ll calc(int now)
    {
            memset(s1,0,sizeof(s1)); memset(s2,0,sizeof(s2));
            ll ret=0;
            for (int i=1;i<=n;i++) if (w[i]>=now) { s1[i]=s1[i-1]+1; s2[i]=s2[i-1]+v[i]; } else { s1[i]=s1[i-1]; s2[i]=s2[i-1]; }
            for (int i=1;i<=m;i++) ret+=(s1[r[i]]-s1[l[i]-1])*(s2[r[i]]-s2[l[i]-1]);
            return ret;
    }
     
    int main()
    {
            init();
            nl=1,nr=maxw;
            while (nl<=nr)
            {
                    int mid=(nl+nr)/2;
                    ll ret=calc(mid);
                    if (ret-s《0) { nr=mid-1; ans=min(ans,s-ret); }
                    else { nl=mid+1; ans=min(ans,ret-s); }
            }
            printf("%lld",ans);
            return 0;
    }
    ---------------------------------------------------------------------------------------------------
  • 相关阅读:
    LeetCode 88. Merge Sorted Array
    LeetCode 75. Sort Colors
    LeetCode 581. Shortest Unsorted Continuous Subarray
    LeetCode 20. Valid Parentheses
    LeetCode 53. Maximum Subarray
    LeetCode 461. Hamming Distance
    LeetCode 448. Find All Numbers Disappeared in an Array
    LeetCode 976. Largest Perimeter Triangle
    LeetCode 1295. Find Numbers with Even Number of Digits
    如何自学并且系统学习计算机网络?(知乎问答)
  • 原文地址:https://www.cnblogs.com/jinkun113/p/4683314.html
Copyright © 2011-2022 走看看