小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 的絕對值最小。請你幫忙求出這個最小值。
輸入格式:
輸入檔案qc.in 。
第一行包含三個整數n,m,s,分別表示礦石的個數、區間的個數和標準值。
接下來的n 行,每行2個整數,中間用空格隔開,第i+1 行表示 i 號礦石的重量 wi 和價值vi。
接下來的m 行,表示區間,每行2 個整數,中間用空格隔開,第i+n+1 行表示區間[li,ri]的兩個端點li 和ri。
注意:不同區間可能重合或相互重疊。
輸出格式:
輸出檔名為qc.out。
輸出只有一行,包含乙個整數,表示所求的最小值。
輸入樣例#1:
5 3 15輸出樣例#1:1 5
2 5
3 5
4 5
5 5
1 5
2 4
3 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≤10^6,0 < s≤10^12,1 ≤li ≤ri ≤n 。
思路+
坑點:二分答案+字首和
1.首先來看給出公式,
公式含義:就是在說從li到ri區間之內的,中間的所有w值超過w的項的個數乘上這些(滿足條件的)礦石的v的和就是我們求所要的y啦!!!
2.因為w的值越大,得出的y越小,是單調的,所以一點需要注意的是l跟r的變化什麼的.
3.要求出的是那個離標準值最近的y.而不是第乙個大於等於或是第乙個大於標準值的y. (此y非彼y???)
4.分析一下題,可以得出w的值只需要在那一坨wi中取就好了,對結果是沒有任何影響的
可是為什麼呢?因為公式...
5.其實我們看到這個題,想到二分答案是不難的,但是如果就直接上二分答案,簡單暴力地求和什麼的,就會超時,時間複雜度o((m*n)log w). 你想啊,暴力的話,兩個迴圈,時間複雜度完美的**:差不多o(m*n)吧. 然後加上二分(log w)就是上面的複雜度了. 然後粗略計算極限資料,僅僅乙個計算y的函式差不多就會爆掉呢(可能吧,我看的dalao的部落格).
6.處理字首和的時候:
因為w是在不斷變化的,所以只需要再重新更新一下字首和就行. 差不多就是將滿足條件的弄上,不行的丟掉吧,大概是這樣.
7.時間複雜度:
應該是o((m+n)*log w)的複雜度(或者o(ac)). 這題就是個二分(log w(列舉的w嘛))+字首和 (因為每個check函式中都有兩個迴圈,乙個迴圈到n,處理字首和,迴圈到m求y.(m個區間嘛~)
8.不開long long見祖宗, 多年oi一場空.
9.要取abs(ans-s)的最小值(絕對值哦!),不要只取ans-s的最小值(因為可能會出來負值),如果不的話的話當ans
10.ans的初始化最大值要夠!!!不要賦成0x77f什麼的,(賦值為1e11差不多是可以的)這個最值(0x77f)對於其中35分的資料是不夠大的,目測來看至少要到1e11吧,然後1e10會wa掉5個測試點(額..65分)呢,因為這個題會爆int,然而0x77f只是最大int.
**:
///view code額...至於格式什麼的,這個就隨你便啦,不順眼可以改嘛~
#include #include
#include
#include
#define ll long long
using
namespace
std;
const
int m = 2e5 + 233
;int
n,m;
ll s;
///注意這裡,s是long long型的,因為資料範圍是到10^12嘛~
intw[m],v[m],l[m],r[m];
ll num[m],sum[m];
///num陣列記錄滿足條件區間內個數.
///sum陣列記錄滿足條件區間內對應的v值的和
int l=1e7,r=0
;ll lmin(ll a,ll b)
int max(int a,int
b)ll check(
int x)///
注意返回值!!!!
*////
memset(sum,0,sizeof(sum));
///memset(num,0,sizeof(num));
for(int i=1;i<=n;i++)///
o((m+n)*log w)
for(int i=1;i<=m;i++)
return
yy;}
void
works()
ans=lmin(ans,abs(s-y));
///注意這裡的s-y要取絕對值
} printf(
"%lld\n
",ans);
}void
reads()
intmain()
額...因為我比較蠢嘛,所以參考了好多dalao的部落格,如下(不是按順序來的哈):
1.
2.
3.
4.
+
xxy 大佬的現場(教)指導
end.
luogu P1314 聰明的質監員
小t 是一名質量監督員,最近負責檢驗一批礦產的質量。這批礦產共有 n 個礦石,從 1到n 逐一編號,每個礦石都有自己的重量 wi 以及價值vi 檢驗礦產的流程是 1 給定m 個區間 li,ri 2 選出乙個引數 w 3 對於乙個區間 li,ri 計算礦石在這個區間上的檢驗值yi 這批礦產的檢驗結果y...
luogu P1314 聰明的質監員
題目描述 小t是一名質量監督員,最近負責檢驗一批礦產的質量。這批礦產共有n個礦石,從1到 n 逐一編號,每個礦石都有自己的重量wi以及價值vi。檢驗礦產的流程是 1 給定m個區間 li,ri 2 選出乙個引數w 3 對於乙個區間 li,ri 計算礦石在這個區間上的檢驗值 yi yi sumv ri ...
洛谷1314 聰明的質監員
noip2011 day2 t1 題目描述 小t 是一名質量監督員,最近負責檢驗一批礦產的質量。這批礦產共有 n 個礦石,從 1到n 逐一編號,每個礦石都有自己的重量 wi 以及價值vi 檢驗礦產的流程是 1 給定m 個區間 li,ri 2 選出乙個引數 w 3 對於乙個區間 li,ri 計算礦石在...