P1314 聪明的质监员

11 篇文章 1 订阅
1 篇文章 0 订阅

P1314 聪明的质监员

    • 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$。注意:不同区间可能重合或相互重叠。

    输出格式:

    一个整数,表示所求的最小值。

    输入输出样例

    输入样例#1: 复制
    5 3 15 
    1 5 
    2 5 
    3 5 
    4 5 
    5 5 
    1 5 
    2 4 
    3 3 
    输出样例#1: 复制
    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 < w_i,v_i≤10^6,0 < S≤10^{12},1 ≤L_i ≤R_i ≤n$ 。

    提示

    思路:

    看一眼这个题目,感觉可以暴力/xyx

    中间没有东西然而我一看数据范围被吓到了真的没有东西

    如 果 范 围 比 较 小 的 话 , 我 们 完 全 可 以 从 1 到 s 扫 一 遍 , 每 次 暴 力 判 断 更 新 答 案 , 但 这 样 一 定 超 时 如果范围比较小的话,我们完全可以从1到s扫一遍,每次暴力判断更新答案,但这样一定超时 ,1s,,

    预 计 得 分 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 ;
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值