[题解]聪明的质检员

// 此博文为迁移而来,写于2015年7月14日,不代表本人现在的观点与看法。原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w6ft.html

1、题目

2、TAG

NOIP提高组;二分答案;前缀和。

3、分析

首先题面一定要看懂,看清(上次我就是没有看懂)。说白了,就是使W取一个最合适的值,使每一个所给区间内满足条件的矿石的数量乘上价值之和,最后计算总和使与S最近。

我们根据分值分布来分析算法:

1、30分算法:O(n^3),首先O(n)进行W值选取的枚举,然后O(n^2)判断+计算;

2、50分算法:O(n^2 log n)。根据每次选取W值我们易发现,所得的总值是一个单调函数,随W增大而减小,且一定存在零点。故为了求得最小值,我们需要得到零点位于那两个整数之间。这样用二分显然比枚举快。O(log n)的二分加上O(n^2)的判断+计算;

3、100分算法:200000的数据显然只能O(n log n)或者O(n)了,但是这道题O(n)很明显不现实。我们的任务在于,如何消去O(n^2)这么大的判断与计算?这里,可以采取前缀和优化——由于每次计算检验值之和的时候,W值固定,故可以用O(n)的时间扫描一遍用a[i]表示前i个矿石满足条件的个数;b[i]表示前i个满足条件的矿石价值之和。故每次询问一个区间的时候可以O(1)直接相减!这样,复杂度就降到了O(n log n)。(这其实是一个很简单的优化但是我想了很久,看来姿势不够)

4、(这个可以无视)70分算法:存在这个分数段就必然存在这种算法对吧。。。这一定是给那些用了前缀和却没有用二分的。。。虽然我觉得很不可思议。

还有一个很重要的数据范围——权值会爆INT。

4、代码

-----------------------------------------------------------------------------------------------------------------

#include<cstdio>
#include<cstring>
#define MAXN 200005
#define INF 1ll<<60

typedef long long ll;

ll max(ll a,ll b) { return (a>b)?a:b; }

ll min(ll a,ll b) { return (a<b)?a:b; }

ll abs(ll a) { return (a<0)?-a:a; }

ll n,m,w[MAXN],v[MAXN],l[MAXN],r[MAXN],maxw,nl,nr;
ll s,ans=INF,s1[MAXN],s2[MAXN];

void init()
{

scanf("%lld %lld %lld",&n,&m,&s);
        for (int i=1;i<=n;i++) { scanf("%lld %lld",&w[i],&v[i]); maxw=max(maxw,w[i]); }
        for (int i=1;i<=m;i++) scanf("%lld %lld",&l[i],&r[i]);
}

ll calc(int now)
{
        memset(s1,0,sizeof(s1)); memset(s2,0,sizeof(s2));
        ll ret=0;
        for (int i=1;i<=n;i++) if (w[i]>=now) { s1[i]=s1[i-1]+1; s2[i]=s2[i-1]+v[i]; } else { s1[i]=s1[i-1]; s2[i]=s2[i-1]; }
        for (int i=1;i<=m;i++) ret+=(s1[r[i]]-s1[l[i]-1])*(s2[r[i]]-s2[l[i]-1]);
        return ret;
}

int main()
{
        init();
        nl=1,nr=maxw;
        while (nl<=nr)
        {
                int mid=(nl+nr)/2;
                ll ret=calc(mid);
                if (ret-s《0) { nr=mid-1; ans=min(ans,s-ret); }
                else { nl=mid+1; ans=min(ans,ret-s); }
        }
        printf("%lld",ans);
        return 0;
}

---------------------------------------------------------------------------------------------------

时间: 2024-11-02 13:59:00

[题解]聪明的质检员的相关文章

[NOIP 2011] 聪明的质检员

聪明的质检员 描述 小 T 是一名质量监督员,最近负责检验一批矿产的质量.这批矿产共有n个矿石,从1到n逐一编号,每个矿石都有自己的重量wi以及价值vi.检验矿产的流程是:1.给定m个区间[Li,Ri]:2.选出一个参数W:3.对于一个区间[Li,Ri],计算矿石在这个区间上的 检验值$Y_i$:\[Y_i=(\sum_j {1}) \times(\sum_j v_j) ,j \in [L_i,R_i] \land \: w_i \geqslant W\] 其中 $j$ 为矿石编号 这批矿产的 

Vijos P1740聪明的质检员

题目 描述 小 T 是一名质量监督员,最近负责检验一批矿产的质量.这批矿产共有n个矿石,从1到n逐一编号,每个矿石都有自己的重量wi以及价值vi.检验矿产的流程是:1.给定m个区间[Li,Ri]:2.选出一个参数W:3.对于一个区间[Li,Ri],计算矿石在这个区间上的检验值Yi:Yi = ∑1*∑vj,j∈[Li, Ri]且wj ≥ W,j是矿石编号这批矿产的检验结果Y 为各个区间的检验值之和.即:Y = ∑Yi,i ∈[1, m]若这批矿产的检验结果与所给标准值S相差太多,就需要再去检验另一

【NOIP2011】聪明的质检员

Description 小 T 是一名质量监督员,最近负责检验一批矿产的质量.这批矿产共有n个矿石,从 1 到n逐一编号,每个矿石都有自己的重量wi以及价值vi.检验矿产的流程是: 1. 给定 m个区间[Li,Ri]: 2. 选出一个参数W: 3. 对于一个区间[Li,Ri],计算矿石在这个区间上的检验值Yi: 这批矿产的检验结果Y为各个区间的检验值之和.即: 若这批矿产的检验结果与所给标准值 S 相差太多,就需要再去检验另一批矿产.小 T 不想费时间去检验另一批矿产,所以他想通过调整参数 W

NOIP2011 聪明的质检员

描述 小 T 是一名质量监督员,最近负责检验一批矿产的质量.这批矿产共有n个矿石,从1到n逐一编号,每个矿石都有自己的重量wi以及价值vi.检验矿产的流程是:1.给定m个区间[Li,Ri]:2.选出一个参数W:3.对于一个区间[Li,Ri],计算矿石在这个区间上的检验值Yi:Yi=(∑j1)∗(∑jvj) ,  j∈[Li,Ri]且wj≥WYi=(∑j1)∗(∑jvj) ,  j∈[Li,Ri]且wj≥Wj是矿石编号 这批矿产的检验结果Y 为各个区间的检验值之和.即:Y=∑i=1mYiY=∑i=

NOIP2015聪明的质检员[二分 | 预处理]

背景 NOIP2011 day2 第二题 描述 小T 是一名质量监督员,最近负责检验一批矿产的质量.这批矿产共有 n 个矿石,从 1到n 逐一编号,每个矿石都有自己的重量 wi 以及价值vi .检验矿产的流程是: 1 .给定m 个区间[Li ,Ri]: 2 .选出一个参数 W: 3 .对于一个区间[Li ,Ri],计算矿石在这个区间上的检验值Yi:Yi=Σ1*Σvj,Σ的循环变量为j,这里j要满足j∈[Li,Ri]且wj≥W,这里j是矿石编号. 这批矿产的检验结果Y为各个区间的检验值之和.ΣYi

CODEVS1138聪明的质检员2011T5

题目描述 Description 小 T 是一名质量监督员,最近负责检验一批矿产的质量.这批矿产共有n 个矿石,从1到n 逐一编号,每个矿石都有自己的重量wi 以及价值vi.检验矿产的流程是:见图 若这批矿产的检验结果与所给标准值S 相差太多,就需要再去检验另一批矿产.小T不想费时间去检验另一批矿产,所以他想通过调整参数W 的值,让检验结果尽可能的靠近标准值S,即使得S-Y 的绝对值最小.请你帮忙求出这个最小值. 思路: 题目描述...像个新定义的题...我真是...比较简单,可以看出w越大,y

洛谷 [P1314] 聪明的质检员(NOIP2011 D2T2)

一道二分答案加前缀和 题目中已经暗示的很明显了 "尽可能靠近" " 最小值" 本题的主要坑点在于 long long 的使用 abs函数不支持long long !!! #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> using namespace std; cons

聪明的质检员

[Problem description] 小 T 是一名质量监督员,最近负责检验一批矿产的质量.这批矿产共有n 个矿石,从1到n 逐一编号,每个矿石都有自己的重量wi 以及价值vi.检验矿产的流程是: 1.给定m 个区间[Li,Ri]: 2.选出一个参数W: 3.对于一个区间[Li,Ri],计算矿石在这个区间上的检验值Yi : 这批矿的检验结果Y 为各个区间的检验值之和.即: 若这批矿产的检验结果与所给标准值S 相差太多,就需要再去检验另一批矿产.小T不想费时间去检验另一批矿产,所以他想通过调

luogu 1314 聪明的质检员

二分答案的边界问题还是要注意 double挨着,int+1-1, 此题用到long long,所以初始化ans要足够大,前缀和优化 依然根据check答案大小左右mid,虽然有s,但是有了+1-1加持所以能够自动推出 #include<bits/stdc++.h> #define int long long #define rep(i,x,y) for(register int i=x;i<=y;i++) using namespace std; const int N=2e6+50;