洛谷P1083 二分答案 差分

2022-06-01 07:27:08 字數 1809 閱讀 3676

題目傳送門『p1083 借教室』

資料範圍:\(1\leq n,m\leq10^6\)

題目意思:給定長度為\(n\)的陣列,和\(m\)次詢問,每次詢問把陣列\([l,r]\)減去\(d\),問第幾次詢問能夠使得陣列能夠存在小於0的數。

樸素做法:對當前\(1..n\)對每個詢問區間做修改(閉區間\([l,r]\)同時減去\(d\)),同時掃瞄當前區間長度\([1,n]\)是否出現\(a[i]\leq0\)。

不難分析時間複雜度是\(o(nm)\),而\((10^6)^2>>10^7\)必然超時。觀察資料\(1e6\)的資料考慮\(nlgn\)做法。

時間複雜度\(o(\text(m)*(n+m))\)

本題關鍵是如果第\(k\)個答案是不符合要求的,那麼後面的都肯定不符合要求(後面減去上一些數,肯定也是小於0的)。即答案具有二段性。我們需要找到乙個臨界點,在這個臨界點區間某個點下一次會被減到負數,而該點後面都是不滿足的情況

因此,我們需要實現乙個函式check(m),使得詢問當前這個點\(m\)是符合的(如果區間每乙個數都是小於原來陣列的那麼是符合的),並且通過二分找到這個符合點的最右端點\(k\)。

再次發現,每一次再修改乙個區間都是同時加上或者減去某個數,最後會詢問當前這個答案m下,是否是符合的,屬於離線修改區間,可以考慮使用差分思想。

方法是對於 \([l,r]\) 加上\(d\)實質上是對於差分陣列\(p\)做\(p[l]+d\),\(p[r+1]-d\)。

即為:

for (int i = l; i <= r; i++)
最後對差分陣列q求字首和:

for (int i = 1; i <= n; i++) q[i] = q[i] + q[i - 1];
這樣即可在\(o(n+m)\)的時間複雜度內得到修改後的陣列。

而暴力是需要\(o(m*n)\)的時間複雜度。

因為總共有\(m\)次詢問,二分\([1,m]\)區間總共是\(o(\text(m))\)次

而每一次是使用差分優化,差分時間複雜度是\(o(n+m)\),因此時間複雜度是\(o(\text(m)*(n+m))\),

綜上比暴力\(o(nm)\)快得多。

//

// author: oceanlvr

#include using namespace std;

typedef long long ll;

static int faster_iostream = () ();

int n, m;

const int maxn = 1e6 + 10;

ll a[maxn];

ll q[maxn];

ll d[maxn], s[maxn], t[maxn];

bool check(int idx)

//對差分做字首和 得到最後m次修改之後的陣列

for (int i = 1; i <= n; i++) q[i] = q[i] + q[i - 1];

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

} return true; //滿足分配條件

}int main() else

} if (r == m) else if (check(r)) else

return 0;

}

洛谷 P1083 借教室 二分 差分

題意 思路 首先可以看出這是乙個比較典型的差分,首先是離線,然後在區間l,r增加幾,這些都是差分的特徵,那麼現在問題就是,怎樣差分?我們可以看出天數是具有單調性的,當在第x天不行的時候那麼x 1肯定也不行,由此可以看出天數是具有二分的特性的,所以我們可以二分天數。include using name...

洛谷P1083 借教室 二分 差分

n天,每天有r i 個教室出租,一共m個訂單,按照先後順序,每個訂單從s天開始到t天結束,每天要借d個,如果所有訂單都能完成,輸出0,哪天教室不夠,輸出到那個訂單的單號。二分可以完成到第幾個訂單,對於每個二分的值,進行差分到這個訂單為止所有的天數,求下字首和,就可以得出對於每一天有沒有超出借出的教室...

洛谷 P1083 借教室(二分 差分)

題目大意 有數列an,每次我們可以選擇乙個區間做減法,問我們第幾次操作會導致乙個區間出現負數。n 1e6 解題思路 線段樹是可以做的,但是貌似這題卡了線段樹。這裡使用二分列舉答案的方法。為什麼這裡適合用差分呢?因為這裡滿足false false true false的結構。每次列舉到乙個點時,我們對...