每日一題之 hiho1769 最長子段

2021-08-21 00:22:21 字數 1597 閱讀 2957

描述

給定乙個陣列a[1..n],你需要選乙個盡可能長的非空連續子段,使得這個子段的和小於等於給定的乙個數 s.

輸入 第一行兩個整數 n,s

第二行 n 個整數,第 i 個整數表示 a[i]

對於 30% 的資料,有1 ≤ n ≤ 103

對於 100% 的資料,有1 ≤ n ≤ 2×105,-109 ≤ a[i] ≤ 109

輸出 輸出滿足題目條件的最長的連續子段的長度,如果不存在這樣的連續子段,輸出 -1。

樣例輸入

3 -1

4 -3 2

樣例輸出

2

思路:

連續的子段和可以利用字首和算出來,最暴力的接髮就是列舉每個子段的和看是否小於等於s,這樣的時間複雜度是o(

n2) o(n

2)

,肯定過不了,肯定有個優化,考慮o(

nlog

n)o (n

logn

)的解法,直覺上可以用二分可以將時間複雜度優化到o(

nlog

n)o (n

logn

), 由於二分的前提條件是序列要有序的,怎麼去構造這個有序的序列b呢?我們令b[

i]b [i

]表示前i個數中所有字首和加上s的最大值。即 b[

i]=m

ax(s

um[i

]+s,

b[i−

1]) b[i

]=ma

x(su

m[i]

+s,b

[i−1

])

這樣保證了b陣列是有序的。然後在b陣列中找第乙個大於sum[i]的值的下標。比如要求子段[i,j]和,那麼就是 su

m[j]

−sum

[i−1

]≤s sum

[j]−

sum[

i−1]

≤s

即 su

m[j]

+s≥s

um[i

] sum

[j]+

s≥su

m[i]

這不等式的左邊就是b陣列中存的數。

#include 

#include

#include

using

namespace

std;

const

int maxn = 1e5+5;

long

long a[maxn*2];

long

long b[maxn*2];

long

long sum[maxn*2];

int main()

b[0] = s;

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

b[i] = max(sum[i]+s,b[i-1]);

int res = -1;

for (int i = n; i >= 1; --i)

cout

<< res << endl;

return

0;}

每日一題之 hiho1744 hohahola

描述 有一種叫作hohahola的飲料,售價是x元一瓶。小hi非常喜歡這種飲料,但是他現在身無分文。不過小hi有n張優惠券,買hohahola時每瓶最多使用一張優惠券,可以使該瓶 減少y元。y x 同時優惠券可以 小hi每 一張優惠券可以獲得z元。請你幫小hi計算通過 若干優惠券,他最多可以買多少瓶...

每日一題之 hiho1304 24點

週末,小hi和小ho都在家待著。在收拾完房間時,小ho偶然發現了一副撲克,於是兩人考慮用這副撲克來打發時間。小ho 玩點什麼好呢?小hi 兩個人啊,不如來玩24點怎麼樣,不靠運氣就靠實力的遊戲。小ho 好啊,好啊。經過若干局遊戲之後 小ho 小hi,你說如果要寫個程式來玩24點會不會很複雜啊?小hi...

每日一題之 hiho197 逆序單詞

描述 在英文中有很多逆序的單詞,比如dog和god,evil和live等等。現在給出乙份包含n個單詞的單詞表,其中每個單詞只出現一次,請你找出其中有多少對逆序單詞。輸入 第1行 1個整數,n,表示單詞數量。2 n 50,000。第2.n 1行 每行1個單詞,只包含小寫字母,每個單詞長度不超過16個字...