ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2020-07-04 14:35:06  阅读:244  来源: 互联网

标签:二分 10 前缀 int sum 质监 mid num LL


 

链接: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\n",ans);
55     
56     return 0;
57 }

 

 

 

 

-

标签:二分,10,前缀,int,sum,质监,mid,num,LL
来源: https://www.cnblogs.com/jiamian/p/13234843.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有