題目描述小 T 是一名品質監督員,最近負責檢驗一批礦產的品質。這批礦產共有n 個礦石,從1到n 逐一編號,每個礦石都有自己的重量wi 以及價值vi。檢驗礦產的流程是:1、給定m 個區間[Li,Ri];2、選出一個參數W;3、對於一個區間[Li,Ri],計算礦石在這個區間上的檢驗值Yi :這個區間上所有重量大於等於W的礦石數目與它們的品質和的乘積。這批礦產的檢驗結果Y 為各個區間的檢驗值之和。若這批礦產的檢驗結果與所給標準值S 相差太多,就需要再去檢驗另一批礦產。小T不想費時間去檢驗另一批礦產,所以他想通過調整參數W 的值,讓檢驗結果儘可能的靠近標準值S,即使得S-Y 的絕對值最小。請你幫忙求出這個最小值。輸入格式第一行包含三個整數 n,m,S,分別表示礦石的個數、區間的個數和標準值。接下來的 n 行,每行2 個整數,中間用空格隔開,第i+1 行表示i 號礦石的重量wi 和價值vi 。接下來的 m 行,表示區間,每行2 個整數,中間用空格隔開,第i+n+1 行表示區間[Li,Ri]的兩個端點Li 和Ri。注意:不同區間可能重合或相互重疊。輸出格式輸出只有一行,包含一個整數,表示所求的最小值。範例輸入5 3 151 52 53 54 55 51 52 43 3範例輸出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 < wi, vi≤106,0 < S≤1012,1≤Li≤Ri≤n。
這道題
當時NOIP2011時,根本不知道咋做
終於AC了,
心情很複雜
有時間要做做類似的題
#include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <ctime>#include <cmath>#define loc#define mxn 200000+10#define mx (long long) 1e100using namespace std;int n,m,mxw;long long S;int l[mxn],r[mxn];int w[mxn],v[mxn];long long s[mxn],sv[mxn];inline long long ck(int x){ long long y=0; for (int i=1;i<=n;++i) { if (w[i]>=x) s[i]=s[i-1]+1,sv[i]=sv[i-1]+v[i]; else s[i]=s[i-1],sv[i]=sv[i-1]; } for (int i=1;i<=m;++i) y+=(s[r[i]]-s[l[i]-1])*(sv[r[i]]-sv[l[i]-1]); return y;}inline long long Abs(long long x){ return x>0?x:-x;}inline void bs(){ int l=0,r=mxw,m; long long min=mx; while (l<=r) { m=(l+r)>>1; long long tmp=ck(m); if (min>Abs(tmp-S)) min=Abs(tmp-S); if (!min) break; if (tmp>S) l=m+1; else r=m-1; } printf("%I64d",min);}int main(){ freopen("qc.in","r",stdin); freopen("qc.out","w",stdout); scanf("%d%d%I64d",&n,&m,&S); for (int i=1;i<=n;++i) { scanf("%d%d",w+i,v+i); if (w[i]>mxw) mxw=w[i]; } for (int i=1;i<=m;++i) scanf("%d%d",l+i,r+i); bs();}