您的位置:首页 > 其它

2011年NOIP提高组 聪明的质检员

2015-10-11 23:01 253 查看
小 T 是一名质量监督员,最近负责检验一批矿产的质量。这批矿产共有n 个矿石,从1到n 逐一编号,每个矿石都有自己的重量wi 以及价值vi。检验矿产的流程是:见图

若这批矿产的检验结果与所给标准值S 相差太多,就需要再去检验另一批矿产。小T不想费时间去检验另一批矿产,所以他想通过调整参数W 的值,让检验结果尽可能的靠近标准值S,即使得S-Y 的绝对值最小。请你帮忙求出这个最小值。




大体思路是二分W然后求Y验证,因为会有重复的区间,暴力求会超时,可以用每次二分的W来O(n)预处理 v[i]前缀和 和 一个区间的符合条件的w[i]数量,还有就是数据范围需要用long long(调了好久才发现QAQ)。

[code]#include<iostream>
#include<cstdio>
#include<cmath>
#define ll long long
using namespace std;
const int size = 400010;
const ll inf = (1ll) << 60;
int n,m;
ll s;
int w[size],v[size];
ll sum[size];
int cnt[size];
ll min(ll a,ll b)
{
    if(a > b)
        return b;
    return a; 
}
ll abs(ll x)
{
    if(x < 0)
        return -x;
    return x;
}
struct sect
{
    int l,r;
}sec[size];
ll ask(int mid)
{
    ll ans = 0;
    for(int i = 1 ; i <= n ; i ++)
    {
        sum[i] = sum[i-1];
        cnt[i] = cnt[i-1];
        if(w[i] > mid)
            sum[i] += v[i] , cnt[i] ++;
    }
    for(int i = 1 ; i <= m ; i ++)
        ans += (cnt[sec[i].r] - cnt[sec[i].l-1]) * (sum[sec[i].r] - sum[sec[i].l-1]);       
    return ans;
}
int main()
{
    scanf("%d%d%lld",&n,&m,&s);
    int maxn = 0;
    for(int i = 1 ; i <= n ; i ++)
        scanf("%d%d",&w[i],&v[i]) , maxn = max(maxn,w[i]);
    for(int i = 1 ; i <= m ; i ++)
        scanf("%d%d",&sec[i].l,&sec[i].r);
    ll minn = inf;
    int l = 0 ,r = maxn+1;
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        ll ans = ask(mid);
        minn = min(minn,abs(ans-s));
        if(ans < s)
            r = mid-1;
        else
            l = mid+1;
    }
    cout<<minn<<endl;
    return 0;
}


传送门 :

codevs 1138

tyvj 1696
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: