• 聪明的质监员(前缀和、二分答案)


    链接:https://ac.nowcoder.com/acm/problem/16597
    来源:牛客网

    时间限制:C/C++ 1秒,其他语言2秒
    空间限制:C/C++ 131072K,其他语言262144K
    64bit IO Format: %lld

    题目描述

    输入描述:

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

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

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

    输出描述:

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

    示例1

    输入

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

    输出

    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 ≤ 106,0 < S ≤ 1012,1 ≤ Li ≤ Ri ≤ n。

    解释一下样例:

    若可加的物品的重量必须大于等于W(4)

    在1-5中只有4,5两个满足条件可加贡献为 2*(5+5)=20;

    在2-4中,只有4一个满足,可加贡献为1*5=5;

    3-3中,没有可以加的贡献0

    故这样当w取4时候,贡献一共为25

    这道题既然要求区间的物品数量和区间的价值之和。我们自然就会想到前缀和。

    我们可以采用一个sum数组来记录从前缀和,sum[i]表示从1到i之间所有有效数字value的和,如果我们要求l,r之间的有效值,则可以用sum[r]-sum[i-1]

    同理采用num数组来记录某个区间段有效物品的个数,num[i]表示从1到i之间有效物品的个数,l,r之间的有效值个数即为num[r]-num[l-1]

    故对应一个区间段的V值即为:(num[r]-num[l-1])*(sum[r]-sum[l-1])

     1 #include <bits/stdc++.h>
     2 typedef long long LL;
     3 #define pb push_back
     4 #define mst(a) memset(a,0,sizeof(a))
     5 const int INF = 0x3f3f3f3f;
     6 const double eps = 1e-8;
     7 const int mod = 1e9+7;
     8 const int maxn = 2e5+10;
     9 using namespace std;
    10 
    11 int n,m; LL s;
    12 LL v[maxn], c[maxn];
    13 LL sum[maxn], num[maxn];
    14 vector<pair<int,int> > vt;
    15 
    16 LL judge(int mid)
    17 {
    18     for(int i=1;i<=n;i++)
    19     {
    20         LL sumt = c[i]>=mid? v[i]:0;
    21         LL numt = c[i]>=mid? 1:0;
    22         sum[i] = sum[i-1] + sumt;
    23         num[i] = num[i-1] + numt;
    24     }
    25     LL res = 0;
    26     for(int i=0;i<m;i++)
    27         res += (num[vt[i].second]-num[vt[i].first-1])*(sum[vt[i].second]-sum[vt[i].first-1]);
    28     return res;
    29 }
    30 
    31 int main()
    32 {
    33     #ifdef DEBUG
    34     freopen("sample.txt","r",stdin); //freopen("data.out", "w", stdout);
    35     #endif
    36     
    37     scanf("%d %d %lld",&n,&m,&s);
    38     for(int i=1;i<=n;i++)
    39         scanf("%lld %lld",&c[i],&v[i]);
    40     for(int i=1;i<=m;i++)
    41     {
    42         int a,b;
    43         scanf("%d %d",&a,&b);
    44         vt.push_back(make_pair(a,b));
    45     }
    46     int L = 0, R =  1e6;
    47     while(L<=R)
    48     {
    49         int mid = (L+R)>>1;
    50         if(judge(mid)>=s) L=mid+1;
    51         else R=mid-1;
    52     }
    53     LL ans = min(abs(judge(L)-s),abs(judge(R)-s));
    54     printf("%lld
    ",ans);
    55     
    56     return 0;
    57 }

    -

  • 相关阅读:
    Netty之WebSocket和四种IO介绍
    java递归展示树形图代码实现以及遇到的问题
    String、String Buffer、String Builder
    物联网的开发应该是什么样子?
    最新 去掉 Chrome 新标签页的8个缩略图
    复化梯形求积分——用Python进行数值计算
    每日设置Bing首页图片为壁纸
    分段二次插值——用Python进行数值计算
    埃尔米特插值问题——用Python进行数值计算
    牛顿插值法——用Python进行数值计算
  • 原文地址:https://www.cnblogs.com/jiamian/p/13234843.html
Copyright © 2020-2023  润新知