原題連線
首先題號好評qwq~ 1314
意思就是:我們要在第 i 個區間 [ li , ri
] 裡找到所有的 j,使得 wj >= w,求出這些 j 的價值總和及符合條件的 j 的個數,那麼這個區間的貢獻就是這個價值總和乘上 j 的個數,然後我們要算所有區間的貢獻的總和 y ,最後輸出 y - s 的絕對值的最小值,其中 w 可以自己定 。
既然 w 可以自己定,那麼乙個很顯然的思路就是我們二分列舉 w,看看哪個 w 最合適不就好啦?
列舉的上下界
我們再回頭看那個公式,顯然若 w 變大,則 y 變小(符合條件的 j 的數量少了); 若 w 變小,則 y 變大;
那麼如果 w 一直變小,直到所有礦石的 wi 都大於我們列舉的這個 w 的話,那麼不就是所有的礦石都被我們給選上了?這時候就會產生最大的 y;
同理,當 w 比所有礦石的 wi 都大時,所有的礦石我們都沒選,這時候就會產生最小的 y ;
所以我們便得出來上下界:
下界:最小的 wi - 1 ;
上界:最大的 wi + 2,這裡為什麼是 + 2 呢?因為 + 1就是所有礦石都不選的情況,我們列舉的時候也要考慮到這種情況。所以再 + 1 就囊括了所有的情況了;
for(int i=1;i<=n;i++)二分過程當我們列舉的 w 求出的 y 過大時,我們應該增大 w 來使得 y 變小來盡量接近 s;當我們列舉的 w 求出的 y 過小時,我們應該減小 w 來使得 y 變大來盡量接近 s;然後我們在求過過程中對 | y - s | 一直取min 就行了。for(int i=1;i<=m;i++) //
m個區間
long
long left=minx_w-1; //
找上下界,這樣就能包含所有情況哦
long
long right=maxn_w+2;
求字首和
最後一部分就是求每個區間的貢獻,顯然我們要求出每個區間符合條件的 j 的個數和價值總和,如果我們對於每個區間我們都要 o(n)的列舉一遍的話, 總的時間複雜度應該是 o(nm log n),log n 是二分次數。對於 2e6 的資料,顯然炸的妥妥的,那怎麼辦呢?
我們可以用字首和鴨,對於我們列舉的每個 w ,我們都先預處理出 價值總和 ,符合條件的個數 這兩個字首和,然後每個區間我們 o(1)算出其貢獻值,這樣的時間複雜度應該是 o((n+m) log n),比較保險~
對於上面的時間複雜度的估算,本蒟蒻很可能算錯了,若發現錯誤請大佬們指出,感激不盡qwq~
那麼怎麼求字首和?
我們設: pre_num [ i ] 為第 1 個礦石到第 i 個礦石中符合條件的礦石數(條件:wj >= w),pre_v [ i ] 為第 1 個礦石到第 i 個礦石中所有符合條件的礦石的價值總和。
那麼我們可以得出遞推方程(狀態轉移方程):
for(int i=1;i<=n;i++)這個還是比較顯然的吧qwq~else
//不滿足條件的話
}
算區間貢獻
字首和做差大家應該都會,我們有了1~n的字首和了,那麼我們求區間 [ li
, ri ] 內的符合條件的礦石數,就是區間 [ 1 , ri ] 內符合條件的礦石數減去區間 [ 1 , li -1] 內符合條件的礦石數,求區間的價值總和同理:
for(int i=1;i<=m;i++) //上完整的ac**:m個區間
#include#include#include
using
namespace
std;
long
long
read()
while(ch>='
0'&&ch<='9'
)
return a*x;
}long
long
n,m,l,r;
long
long pre_num[2000001
];long
long nl[2000001],nr[2000001
];long
long
maxn_w,minx_w,minx,s;
long
long pre_v[2000001
];struct
node
a[2000001
];int work(long
long w) //
我們列舉的w
for(int i=1;i<=n;i++) //
預處理
else
//不滿足條件的話
}long
long y=0
;
for(int i=1;i<=m;i++) //
m個區間
long
long s=y-s;
if(s<0) s=-s; //
手寫取絕對值,用函式總有一堆奇怪的錯誤
if(s//
更新答案
if(y>s) return
1; //
y太大,需要增大w來減小y
if(yreturn
0; //
y太小,需要減小w來增大y
if(y==s) return -1; //
正好,一定是最優解
}int
main()
for(int i=1;i<=m;i++) //
m個區間
long
long left=minx_w-1; //
找上下界,這樣就能包含所有情況哦
long
long right=maxn_w+2
;
while(left<=right)
printf(
"%lld
",minx);
return0;
}
P1314 聰明的質監員
小t 是一名質量監督員,最近負責檢驗一批礦產的質量。這批礦產共有 n 個礦石,從 1到n 逐一編號,每個礦石都有自己的重量 wi 以及價值vi 檢驗礦產的流程是 1 給定m 個區間 li,ri 2 選出乙個引數 w 3 對於乙個區間 li,ri 計算礦石在這個區間上的檢驗值yi 這批礦產的檢驗結果y...
P1314 聰明的質監員
我是題面 讀完題後,我們會發現這道題的題意非常簡單,大意就是有n件物品,m個區間,求每個區間檢驗值之和,通過改變引數使標準值與檢驗值的差的絕對值最小 很明顯,檢驗值的變動只與引數有關,我們可以二分引數來搜尋答案 由題意可知,引數至小為0,至大為所有物品中最大的重量,再大則與至大值意義相同 那麼每次用...
P1314 聰明的質監員
p1314 聰明的質監員 這題還是挺有名的,然而是個假題 原因 但是它的思維方式還是挺重要的。思路 我們發現乙個w可以唯一確定乙個y,但是w不知道。像這種情況很容易想到二分。二分可以在 o log n 的時間內多個條件,有時候可以先假裝二分過了去想題,發現不用二分再把二分去掉。但是再算一算,只加上二...