-
- 5.5<small>K</small>通过
- 21.1<small>K</small>提交
题目描述
小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扫一遍,每次暴力判断更新答案,但这样一定超时
预计得分10分
算了,上代码
#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 ;
}