Luogu P1314 [NOIp提高組2011]聰明的質監員


題目描述
小T 是一名質量監督員,最近負責檢驗一批礦產的質量。這批礦產共有 n 個礦石,從 1到n 逐一編號,每個礦石都有自己的重量 wi 以及價值vi 。檢驗礦產的流程是:
1 、給定m 個區間[Li,Ri];
2 、選出一個參數 W;
3 、對於一個區間[Li,Ri],計算礦石在這個區間上的檢驗值Yi:
這裏寫圖片描述
這批礦產的檢驗結果Y 爲各個區間的檢驗值之和。即:Y1+Y2…+Ym
若這批礦產的檢驗結果與所給標準值S 相差太多,就需要再去檢驗另一批礦產。小T
不想費時間去檢驗另一批礦產,所以他想通過調整參數W 的值,讓檢驗結果儘可能的靠近
標準值S,即使得S-Y 的絕對值最小。請你幫忙求出這個最小值。


二分W ,前綴和優化。

代碼

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxn=200010;
int w[maxn],v[maxn],l[maxn],r[maxn];
long long sum1[maxn],sum2[maxn];
int main(){
    int n,m,maxw=0;
    long long s;
    cin>>n>>m>>s;
    for(int i=1;i<=n;i++) scanf("%d%d",&w[i],&v[i]),maxw=max(maxw,w[i]);
    for(int i=0;i<m;i++) scanf("%d%d",&l[i],&r[i]);
    int L=1,R=maxw;
    LL ans;
    while(L<R-1){
        int M=L+R>>1;
        LL a=0;
        sum1[0]=0;
        sum2[0]=0;
        for(int i=1;i<=n;i++){
            sum1[i]=sum1[i-1];
            sum2[i]=sum2[i-1];
            if(w[i]>=M) sum1[i]++,sum2[i]+=v[i];
        }
        for(int i=0;i<m;i++)
            a+=(sum1[r[i]]-sum1[l[i]-1])*(sum2[r[i]]-sum2[l[i]-1]);
        if(a>=s) L=M;
        else R=M;
    }
   //二分後不知道什麼是答案,就複製粘貼了一波...
    LL a=0;
    sum1[0]=0;

    sum2[0]=0;
    for(int i=1;i<=n;i++){
        sum1[i]=sum1[i-1];
        sum2[i]=sum2[i-1];
        if(w[i]>=R) sum1[i]++,sum2[i]+=v[i];
    }
    for(int i=0;i<m;i++)
        a+=(sum1[r[i]]-sum1[l[i]-1])*(sum2[r[i]]-sum2[l[i]-1]);
    ans=abs(a-s);
    sum1[0]=0;
    sum2[0]=0;
    a=0;
    for(int i=1;i<=n;i++){
        sum1[i]=sum1[i-1];
        sum2[i]=sum2[i-1];
        if(w[i]>=L) sum1[i]++,sum2[i]+=v[i];
    }
    for(int i=0;i<m;i++)
        a+=(sum1[r[i]]-sum1[l[i]-1])*(sum2[r[i]]-sum2[l[i]-1]);
    cout<<min(ans,abs(a-s))<<endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章