NOIP2011聰明的質監員題解
631. [NOIP2011] 聰明的質監員
★★ 輸入文件:qc.in
輸出文件:qc.out
簡單對比
時間限制:1 s 內存限制:128 MB
【問題描述】
小 T 是一名質量監督員,最近負責檢驗一批礦產的質量。這批礦產共有n個礦石,從 1 到n逐一編號,每個礦石都有自己的重量wi以及價值vi。檢驗礦產的流程是:
1. 給定 m個區間[Li,Ri];
2. 選出一個參數W;
3. 對於一個區間[Li,Ri],計算礦石在這個區間上的檢驗值Yi:
Yi=∑j1×∑jvj, j∈[Li,Ri]且 wj≥W,j是礦石編號
這批礦產的檢驗結果Y為各個區間的檢驗值之和。即:
- 若這批礦產的
檢驗結果
- 與所給標準值 S 相差太多,就需要再去檢驗另一批礦產。小 T 不想費時間去檢驗另一批礦產,所以他想通過調整參數 W 的值,讓
檢驗結果
- 盡可能的靠近標準值 S,即使得
S?Y的絕對值最小。請你幫忙求出這個最小值。
【輸入】
輸入文件 qc.in。
第一行包含三個整數n,m,S,分別表示礦石的個數、區間的個數和標準值。
接下來的n 行,每行2 個整數,中間用空格隔開,第i+1 行表示i 號礦石的重量wi 和價值vi 。
接下來的m 行,表示區間,每行2 個整數,中間用空格隔開,第i+n+1 行表示區間[Li,Ri]的兩個端點Li 和Ri。註意:不同區間可能重合或相互重疊。
【輸出】
輸出文件名為qc.out。
輸出只有一行,包含一個整數,表示所求的最小值。
【輸入輸出樣例】
qc.in
5 3 15
1 5
2 5
3 5
4 5
5 5
1 5
2 4
3 3
qc.out
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≤10^6,0 < S≤10^12,1≤Li≤Ri≤n。
這道題一開始看到Σ還以為是數學題,果斷跳過,然後發現自己錯了……
然後又以為是平衡樹,然而昨天雖然剛打了平衡樹卻因為模板錯誤而沒能學習區間操作,果斷心虛。於是打了最暴力的暴力,強行水了5分。
這道題最重要的有兩點,第一,前綴和,第二,二分。
先解釋前綴和,這個很容易理解,就是sumv[i]為在i之前所有high不小於w的value的前綴和sumw[i]為在i之前高度不小於w的個數。
然後就是二分,考試的時候以為是三分,之前沒打過,打掛了。如果以abs(Y-S)為y軸,w為x軸,那麽圖像是一個絕對值函數,類似二次函數,很容易讓人想到三分,然而值得註意的是Y本身是隨w增大而遞減的,而Y-S也是如此,我們就可以利用這個性質不斷地二分w,使Y無限的去接近S,Y大於0就右移,反之左移,記得開long long。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<queue> 6 #include<algorithm> 7 #include<cmath> 8 #include<map> 9 using namespace std; 10 int n,m; 11 long long s; 12 struct no{ 13 int va; 14 int w; 15 }node[2000005]; 16 struct qu{ 17 int li,ri; 18 }que[2000004]; 19 long long sumw[2000005],sumv[2000005]; 20 long long check(int w){ 21 memset(sumv,0,sizeof(sumv)); 22 memset(sumw,0,sizeof(sumw)); 23 for(int i=1;i<=n;i++) 24 { 25 sumw[i]=sumw[i-1]; 26 sumv[i]=sumv[i-1]; 27 if(node[i].w>=w) 28 { 29 sumw[i]++; 30 sumv[i]+=node[i].va; 31 } 32 } 33 long long ans=0; 34 for(int i=1;i<=m;i++) 35 { 36 ans+=(sumv[que[i].ri]-sumv[que[i].li-1])*(sumw[que[i].ri]-sumw[que[i].li-1]); 37 } 38 return ans; 39 } 40 long long minn(long long a,long long b){ 41 if(a>b)return b; 42 return a; 43 } 44 long long llab(long long a){ 45 if(a<0) 46 return -a; 47 return a; 48 } 49 int main(){ 50 scanf("%d%d%lld",&n,&m,&s); 51 int mx=0; 52 for(int i=1;i<=n;i++) 53 { 54 scanf("%d%d",&node[i].w,&node[i].va); 55 mx=max(mx,node[i].w); 56 } 57 for(int i=1;i<=m;i++) 58 scanf("%d%d",&que[i].li,&que[i].ri); 59 int li=1,ri=mx; 60 long long ans=-1; 61 while(li<=ri) 62 { 63 int mid=(li+ri)/2; 64 long long x=check(mid); 65 if(ans==-1)ans=llab(x-s); 66 ans=minn(ans,llab(x-s)); 67 if(x>s) 68 li=mid+1; 69 else 70 ri=mid-1; 71 } 72 printf("%lld\n",ans); 73 //while(1); 74 return 0; 75 }View Code
NOIP2011聰明的質監員題解