标签:表示 lld check 中间 img closed lib int math
★★ 输入文件:qc.in
输出文件:qc.out
简单对比
时间限制:1 s 内存限制:128 MB
【问题描述】
小 T 是一名质量监督员,最近负责检验一批矿产的质量。这批矿产共有n个矿石,从 1 到n逐一编号,每个矿石都有自己的重量wi以及价值vi。检验矿产的流程是:
1. 给定 m个区间[Li,Ri];
2. 选出一个参数W;
3. 对于一个区间[Li,Ri],计算矿石在这个区间上的检验值Yi:
这批矿产的检验结果Y为各个区间的检验值之和。即:
检验结果
检验结果
S?Y的绝对值最小。请你帮忙求出这个最小值。
【输入】
输入文件 qc.in。
第一行包含三个整数n,m,S,分别表示矿石的个数、区间的个数和标准值。
接下来的n 行,每行2 个整数,中间用空格隔开,第i+1 行表示i 号矿石的重量wi 和价值vi 。
接下来的m 行,表示区间,每行2 个整数,中间用空格隔开,第i+n+1 行表示区间[Li,Ri]的两个端点Li 和Ri。注意:不同区间可能重合或相互重叠。
【输出】
输出文件名为qc.out。
输出只有一行,包含一个整数,表示所求的最小值。
【输入输出样例】
qc.in
5 3 15
1 5
2 5
3 5
4 5
5 5
1 5
2 4
3 3
qc.out
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。
这道题一开始看到Σ还以为是数学题,果断跳过,然后发现自己错了……
然后又以为是平衡树,然而昨天虽然刚打了平衡树却因为模板错误而没能学习区间操作,果断心虚。于是打了最暴力的暴力,强行水了5分。
这道题最重要的有两点,第一,前缀和,第二,二分。
先解释前缀和,这个很容易理解,就是sumv[i]为在i之前所有high不小于w的value的前缀和sumw[i]为在i之前高度不小于w的个数。
然后就是二分,考试的时候以为是三分,之前没打过,打挂了。如果以abs(Y-S)为y轴,w为x轴,那么图像是一个绝对值函数,类似二次函数,很容易让人想到三分,然而值得注意的是Y本身是随w增大而递减的,而Y-S也是如此,我们就可以利用这个性质不断地二分w,使Y无限的去接近S,Y大于0就右移,反之左移,记得开long long。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<queue> 6 #include<algorithm> 7 #include<cmath> 8 #include<map> 9 using namespace std; 10 int n,m; 11 long long s; 12 struct no{ 13 int va; 14 int w; 15 }node[2000005]; 16 struct qu{ 17 int li,ri; 18 }que[2000004]; 19 long long sumw[2000005],sumv[2000005]; 20 long long check(int w){ 21 memset(sumv,0,sizeof(sumv)); 22 memset(sumw,0,sizeof(sumw)); 23 for(int i=1;i<=n;i++) 24 { 25 sumw[i]=sumw[i-1]; 26 sumv[i]=sumv[i-1]; 27 if(node[i].w>=w) 28 { 29 sumw[i]++; 30 sumv[i]+=node[i].va; 31 } 32 } 33 long long ans=0; 34 for(int i=1;i<=m;i++) 35 { 36 ans+=(sumv[que[i].ri]-sumv[que[i].li-1])*(sumw[que[i].ri]-sumw[que[i].li-1]); 37 } 38 return ans; 39 } 40 long long minn(long long a,long long b){ 41 if(a>b)return b; 42 return a; 43 } 44 long long llab(long long a){ 45 if(a<0) 46 return -a; 47 return a; 48 } 49 int main(){ 50 scanf("%d%d%lld",&n,&m,&s); 51 int mx=0; 52 for(int i=1;i<=n;i++) 53 { 54 scanf("%d%d",&node[i].w,&node[i].va); 55 mx=max(mx,node[i].w); 56 } 57 for(int i=1;i<=m;i++) 58 scanf("%d%d",&que[i].li,&que[i].ri); 59 int li=1,ri=mx; 60 long long ans=-1; 61 while(li<=ri) 62 { 63 int mid=(li+ri)/2; 64 long long x=check(mid); 65 if(ans==-1)ans=llab(x-s); 66 ans=minn(ans,llab(x-s)); 67 if(x>s) 68 li=mid+1; 69 else 70 ri=mid-1; 71 } 72 printf("%lld\n",ans); 73 //while(1); 74 return 0; 75 }
标签:表示 lld check 中间 img closed lib int math
原文地址:http://www.cnblogs.com/liutianrui/p/7287257.html