HDU 6012 列舉 二分

2021-07-26 08:22:56 字數 2800 閱讀 3602

問題描述

這幾天lotus對培養盆栽很感興趣,於是她想搭建乙個溫室來滿足她的研究慾望。

lotus將所有的n

n株盆栽都放在新建的溫室裡,所以所有盆栽都處於完全相同的環境中。

每一株盆栽都有乙個最佳生長溫度區間[l,r][l

,r],在這個範圍的溫度下生長會生長得最好,但是不一定會提供最佳的研究價值(lotus認為研究發育不良的盆栽也是很有研究價值的)。

lotus進行了若干次試驗,發現若第i

i株盆栽的生長溫度適宜,可以提供a_ia​

i​​的研究價值;若生長溫度超過了適宜溫度的上限,能提供b_ib​

i​​的研究價值;若生長溫度低於適宜溫度的下限,則能提供c_ic​

i​​的研究價值。

現在通過試驗,lotus已經得知了每一株盆栽的適宜生長溫度範圍,也知道了它們的aa、b

b、cc的值。你需要根據這些資訊,給溫室選定乙個溫度(這個溫度可以是任意實數),使得lotus能獲得的研究價值最大。

輸入描述

多組資料,第一行乙個整數t

t表示資料組數

每組資料第一行乙個整數n\in[1,50000]n∈

[1,5

0000

],表示盆栽數量

接下來n

n行每行五個整數l_i,r_i,a_i,b_i,c_i\in[1, 10^9]l​

i​​,

r​i​

​,a​

i​​,

b​i​

​,c​

i​​∈

[1,1

0​9​

​],意義如上所述

輸出描述

每組資料輸出一行乙個整數表示答案
輸入樣例

1

55 8 16 20 12

10 16 3 13 13

8 11 13 1 11

7 9 6 17 5

2 11 20 8 5

輸出樣例

83

這題我寫的方法有點蠢。

我是列舉所有邊界的座標,因為一開始我就認為這樣列舉,就可以包含所有情況,事實上這樣是錯的。比如兩個區間[1,2]和[3,4],我只會列舉1,2,3,4這四個點,但是很顯然還有溫度是3.5的情況沒有考慮到,所以後來我直接把上下界排好序後,把相鄰兩個邊界的中點也作為列舉的物件。

對於每乙個列舉的溫度t,我們只需要考慮三個部分:

1. 有多少個區間的右端點r在比t小,對於這些區間來說,溫度比適宜的高,研究價值為b。

2. 有多少個區間的右端點l在比t大,對於這些區間來說,溫度比適宜的低,研究價值為c。

3. 除了1和2所包括的區間,剩下的區間就是滿足適宜條件的,研究價值為a。

顯然上面三個部分互相不會重複,那麼需要解決的問題就是,列舉之後如何快速計算上面的結果。

可以感覺到1和2能用二分來計算。首先我們要把所有的區間按左端點排序存起來lx,接著按右端點排序存起來rx。

對於lx,預處理出乙個a的字首和sumal和乙個c的字首和sumc。

對於rx,預處理出乙個a的字首和sumar和乙個b的字首和sumb。

然後每次列舉溫度t,找到lx中比t大的位置以及rx中比t小的位置,然後用a的總和suma減去這兩部分的a的總價值,再加上第一段的c的價值和和第二段的b的價值和即可。

思路不像官方題解中那麼好寫,具體看**。

#include using namespace std;

const int maxn = 50005;

struct node

}l[maxn], r[maxn];

long long a[maxn], b[maxn], c[maxn];

long long sumal[maxn], sumar[maxn], sumb[maxn], sumc[maxn];

double lx[maxn], rx[maxn];

int main() ;

r[i] = (node) ;

vec.push_back(ll); vec.push_back(rr);

}sort (l + 1, l + 1 + n);

sort (r + 1, r + 1 + n);

long long suma = 0;

for (int i = 1; i <= n; i++) suma += a[i];

for (int i = 1; i <= n; i++)

for (int i = 1; i <= n; i++)

for (int i = 1; i <= n; i++) lx[i] = l[i].x;

for (int i = 1; i <= n; i++) rx[i] = r[i].x;

long long ans = 0;

sort (vec.begin(), vec.end());

vec.erase( unique( vec.begin(), vec.end() ), vec.end() );

int cnt = vec.size();

for (int i = 1; i < cnt; i++)

vec.push_back((vec[i] + vec[i - 1]) / 2.0);

sort (vec.begin(), vec.end());

cnt = vec.size();

for (int i = 0; i < cnt; i++)

ans = max(ans, max(sumb[n], sumc[n]));

printf("%i64d\n", ans);

}return 0;

}

hdu 5265 二分 列舉

解題思路 首先對每個數進行去模,這樣得到的數就會是 0,p 1 的範圍,接下來就是如何組合的問題了。這裡要考慮到模的性質了,假設取的兩個數分別為i,j,其中i j,如果當前數i p 1 2,那麼就會出現兩種情況 1 j p 1 2,這樣算出來的結果必定是i j p,i和j肯定都要盡可能大 2 j p...

瘋牛(二分列舉)

描述 農夫 john 建造了一座很長的畜欄,它包括n 2 n 100,000 個隔間,這些小隔間依次編號為x1,xn 0 xi 1,000,000,000 但是,john的c 2 c n 頭牛們並不喜歡這種布局,而且幾頭牛放在乙個隔間裡,他們就要發生爭鬥。為了不讓牛互相傷害。john決定自己給牛分配...

poj 3273 二分列舉

題意 給出乙個有n個資料的陣列,將其分為連續的m份,找到一種分法,是的m份中最大乙份總和最小 參考部落格 題解 一種方案中最大的那部分總和num存在乙個範圍,num總大於等於陣列中最大的那個數,總小於等於整個陣列的和。得到了乙個範圍a b,用二分法不斷縮小範圍,比如第一次取mid a a b 2,那...