-
- 5.5K通过
- 21.1K提交
- 标签 二分答案 前缀和 数论,数学 NOIp提高组 2011 高性能
- 难度 提高+/省选-
- 时空限制 1000ms / 128MB
题目描述
小T
是一名质量监督员,最近负责检验一批矿产的质量。这批矿产共有 $n$ 个矿石,从 $1$到$n$ 逐一编号,每个矿石都有自己的重量 $w_i$ 以及价值$v_i$ 。检验矿产的流程是:1 、给定$m$个区间$[L_i,R_i]$;
2 、选出一个参数$ W$;
3 、对于一个区间$[L_i,R_i]$,计算矿石在这个区间上的检验值$Y_i$:
这批矿产的检验结果$Y$ 为各个区间的检验值之和。即:$Y_1+Y_2...+Y_m$
若这批矿产的检验结果与所给标准值$S$ 相差太多,就需要再去检验另一批矿产。
小T
不想费时间去检验另一批矿产,所以他想通过调整参数W 的值,让检验结果尽可能的靠近标准值$S$,即使得$S-Y$ 的绝对值最小。请你帮忙求出这个最小值。输入输出格式
输入格式:
第一行包含三个整数$n,m,S$,分别表示矿石的个数、区间的个数和标准值。
接下来的$n$行,每行$2$个整数,中间用空格隔开,第$i+1$行表示$i$号矿石的重量$w_i$和价值$v_i$。
接下来的$m$ 行,表示区间,每行$2$ 个整数,中间用空格隔开,第$i+n+1$ 行表示区间$[L_i,R_i]$的两个端点$L_i$ 和$R_i$。注意:不同区间可能重合或相互重叠。
输出格式:
一个整数,表示所求的最小值。
输入输出样例
说明
【输入输出样例说明】
当$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 < w_i,v_i≤10^6,0 < S≤10^{12},1 ≤L_i ≤R_i ≤n$ 。
提示
思路:
看一眼这个题目,感觉可以暴力/xyx
中间没有东西 然而我一看数据范围被吓到了 真的没有东西 如 果 范 围 比 较 小 的 话 , 我 们 完 全 可 以 从 1 到 s 扫 一 遍 , 每 次 暴 力 判 断 更 新 答 案 , 但 这 样 一 定 超 时 如果范围比较小的话,我们完全可以从1到s扫一遍,每次暴力判断更新答案,但这样一定超时 如果范围比较小的话,我们完全可以从1到s扫一遍,每次暴力判断更新答案,但这样一定超时
预 计 得 分 10 分 预计得分10分 预计得分10分
算 了 , 上 代 码 \color{red}{算了,上代码} 算了,上代码
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #define int long long #define maxn 2000020 using namespace std ; int n , m , w[maxn] , v[maxn] , pre[maxn] , s_w[maxn],sum ; int W ; struct dy{ int l , r ; }a[maxn] ; int ans = 9999999999999; int s , Y ; int read() { int x = 0 , f = 1 ; char s = getchar() ; while(s > '9' || s < '0') {if(s == '-') f = -1 ; s = getchar() ;} while(s <='9' && s >='0') {x = x * 10 + (s-'0'); s = getchar() ;} return x*f ; } bool check(int mid) { Y = 0 , sum = 0 ; for(int i = 1 ; i <= n ; i ++) { pre[i] = s_w[i] = 0 ; } for(int i = 1 ; i <= n ; i ++) { if(w[i] >= mid) pre[i] = pre[i-1] + 1 , s_w[i] = s_w[i-1] + v[i] ; else pre[i] = pre[i-1] , s_w[i] = s_w[i-1]; } for(int i = 1 ; i <= m ; i ++) Y+=(pre[a[i].r]-pre[a[i].l-1])*(s_w[a[i].r]-s_w[a[i].l-1]); sum = llabs(Y-s); if(Y>s) return true; else return false; } signed main () { //n = read() , m = read() , s = read() ; scanf("%lld%lld%lld",&n,&m,&s) ; for(int i = 1 ; i <= n ; i ++) { //w[i] = read() , v[i] = read(); scanf("%d%d",&w[i],&v[i]) ; } for(int i = 1 ; i <= m ; i ++) { ///a[i].l = read() , a[i].r = read() ; scanf("%d%d",&a[i].l,&a[i].r) ; } int l = 0 , r = s ; while(l <= r) { int mid = (l+r) >> 1 ; if(check(mid)) { l = mid + 1 ; }else { r = mid - 1 ; } if(sum < ans ) ans = sum ; } printf("%lld",ans) ; return 0 ; }