目錄html
\(n\) 家飯店,\(m\) 張餐票,第 \(i\) 家和第 \(i+1\) 家飯店之間的距離是 \(A_i\) ,在第 \(i\) 家飯店用掉第 \(j\) 張餐票會得到 \(B_{i, j}\) 的好感度,能夠從任意一個飯店出發,求好感度減通過的距離和的差的最大值。c++
\(2 \le n \le 5000, 1 \le m \le 200, 1 \le A_{i, j}, B_{i, j} \le 10^9\)git
作題千萬條,看題第一條。app
顯然咱們不會走回頭路,那麼每次咱們選擇的必定是一段連續區間 \([l, r]\) 。函數
考慮每一個 \(B_{i, j}\) 對於哪些區間有貢獻,找到左右第一個比它的 \(B_{x, j}, B_{y, j} \ge B_{i, j}\) ,那麼它貢獻的區間其實就是 \(l \in (x, i], r \in [i, y)\) 。優化
咱們利用單調棧算出端點,而後矩形加利用二維差分實現便可。spa
\(\mathcal O(n^2 + nm)\)debug
有一個雙端隊列。code
首先將 \(n\) 個數 \(1\sim n\) 從小到大任意先後地添入隊列。而後任意先後地彈出隊列,求最後彈出來的排列中,第 \(k\) 個數爲 \(1\) 的排列有多少種。
\(1 \le k \le n \le 2000\)
一開始添完的序列性質顯然是將 \(1\) 分紅兩段,左邊遞減,右邊遞增。
因爲構造合法序列是左右彈元素,那麼性質就比較好推了。
先考慮最後 \(n - k\) 個數的方案,若是咱們肯定了前 \(k\) 個數,那麼剩下的 \(n - k\) 個數是由一個單調隊列彈出來的,除了最後一次只能彈一個,別的每次都有兩種選擇,因此方案是 \(2^{\max(0, n - k - 1)}\) 。
而後前面拆分紅至多兩個降低子序列,這個和 這道題 是同樣的。
咱們如今只須要知足第一個限制了,因爲第 \(k\) 個數是須要最小值,用至多選 \(k\) 個和 \(k - 1\) 個差分一下便可。
而後利用以前那個題的組合數結論就能夠作到 \(\mathcal O(n)\) 了。
其實那個組合數有個更優美的形式,也就是 \(\displaystyle {n + m \choose m} - {n + m \choose m - 1}\) ,意義明顯許多。
有 \(n\) 個高爲 \(1\) 的矩形,第 \(i\) 個矩形 \(y\) 軸範圍爲 \([i - 1, i]\) ,\(x\) 軸範圍爲 \([l_i, r_i]\) 。
須要橫向移動一些矩形,使得全部矩形是連通的(角也算),對於一個矩形,橫向移動 \(x\) 距離的代價爲 \(x\) ,求出最小代價。
\(1 \le n \le 10^5, 1 \le l \le r \le 10^9\)
首先考慮暴力 \(dp\) 即令 \(f_{i, j}\) 爲第 \(i\) 層矩形右端點爲 \(j\) ,前 \(i\) 層已經聯通所須要的最小代價。
令 \(len_i = r_i - l_i\) ,每次只須要兩條線段相交便可。轉移十分顯然:
\[ \begin{aligned} f_{i, p} &= |r_i - p| + \min_{p - len_i \le j, p \ge j - len_{i - 1}} f_{i - 1, j} \\ &= |r_i - p| + \min_{j - len_{i - 1} \le p \le j + len_i} f_{i - 1, j} \end{aligned} \]
咱們能夠把 \(f_i\) 看作一個關於 \(p\) 的函數,設 \(g_i(p) = |r_i - p|\) ,那麼形式爲:
\[ f_i(p) = g_i(p) + \min_{j - len_{i - 1} \le p \le j + len_i} f_{i - 1}(j) \]
不難觀察到函數這個圖像實際上是一個分段一次函數,且斜率從 \(-(i - 1), - (i - 2), \cdots, 0, \cdots, i - 2, i - 1\) 遞增(拆開重合點)。(不難利用概括證實)其實也是一個凹函數,最小值在 \(k = 0\) 處取得。
那麼考慮後面那個 \(\min\) 等價於把 \(k_x < 0\) 的部分向左平移 \(len_{i - 1}\) (由於咱們想盡可能向右取),\(k_x > 0\) 的部分向右平移 \(len_i\) ,而後最後全局加上 \(g_i\) 就好了。
咱們其實能夠用 \(Splay\) 維護這個凸殼,每次只須要支持區間加一次函數,全局平移便可。
但顯然能夠更方便地解決,因爲最後咱們只須要求 \(k = 0\) 時候的函數值,咱們利用對頂堆維護 \(k < 0, k > 0\) 的位置,每次討論一下插入的絕對值函數的 \(0\) 點位置便可。
討論的時候能夠順便計算一下當前的答案。
對於加絕對值函數,而且取 \(\min, \max\) 的 \(dp\) 均可以考慮是否存在凸殼,而後經過 線段樹/ \(Splay\) / 對頂堆 維護這個 \(dp\) 值便可。
#include <bits/stdc++.h> #define For(i, l, r) for (register int i = (l), i##end = (int)(r); i <= i##end; ++i) #define Fordown(i, r, l) for (register int i = (r), i##end = (int)(l); i >= i##end; --i) #define Rep(i, r) for (register int i = (0), i##end = (int)(r); i < i##end; ++i) #define Set(a, v) memset(a, v, sizeof(a)) #define Cpy(a, b) memcpy(a, b, sizeof(a)) #define debug(x) cout << #x << ": " << (x) << endl using namespace std; typedef long long ll; template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; } template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; } inline int read() { int x(0), sgn(1); char ch(getchar()); for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1; for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48); return x * sgn; } void File() { #ifdef zjp_shadow freopen ("E.in", "r", stdin); freopen ("E.out", "w", stdout); #endif } const int N = 1e5 + 1e3; int n, l[N], r[N], len[N]; ll tl, tr, ans; priority_queue<ll> L; priority_queue<ll, vector<ll>, greater<ll>> R; int main () { File(); For (i, 1, n = read()) l[i] = read(), r[i] = read(), len[i] = r[i] - l[i]; L.push(r[1]); R.push(r[1]); For (i, 2, n) { tl -= len[i - 1]; tr += len[i]; ll lp = L.top() + tl, rp = R.top() + tr; if (lp <= r[i] && r[i] <= rp) L.push(r[i] - tl), R.push(r[i] - tr); else if (r[i] >= rp) { ans += r[i] - rp; R.pop(); L.push(rp - tl); R.push(r[i] - tr); R.push(r[i] - tr); } else { ans += lp - r[i]; L.pop(); R.push(lp - tr); L.push(r[i] - tl); L.push(r[i] - tl); } } printf ("%lld\n", ans); return 0; }
有 \(n = a + b\) 我的,其中有 \(a\) 我的是誠實的,\(b\) 我的是不友好的。每次你能夠問 \(x\) : \(y\) 是否是一個誠實的人。若是 \(x\) 是誠實的,那麼必定會回答真正的答案。不然,他會隨便告訴你一個結果。(交互庫有必定策略地回答。)
如今告訴你 \(a, b\) ,你須要肯定是否必定能問出來。若是問不出來輸出 Impossible
。若是能問出來,須要在 \(2n\) 步內問出來。
首先咱們考慮何時是 Impossible
,顯然當 \(b \ge a\) 的時候,\(b\) 能夠很好的隱藏在 \(a\) 中。由於問任意一我的,\(b\) 均可以根據 \(a\) 的決策,來顛倒黑白。只有當 \(a\) 超過 \(n\) 的一半的時候,咱們問任意一我的均可以根據 \(\text{Y, N}\) 中較多的那項肯定類別。
接下來,咱們不難想到一個亂搞。就是一開始隨機問幾我的,而後問全部人他的類別,就能夠肯定類別了。若是是老實人,而後就能夠一遍問它就能獲得全部人的類別了。咱們打亂一下詢問順序,那麼這樣指望下是 \(3n\) 的。
咱們其實能夠繼續優化一下亂搞,加上以下幾個優化:
指望應該是 \(1.5n\) 的?而後全都加上。。就能夠過啦qwq(我也是交了十幾發才艹過的。。)
顯然有肯定性作法,咱們須要基於這樣一個結論,若是 \(x\) 說 \(y\) 是不友好的,那麼 \(x, y\) 確定不可能同時是誠實的,若是咱們忽略他們,剩下的老實人個數仍然大於一半。
咱們用個棧,把每一個人放進去,若是棧頂這我的說當前這我的是不友好的,咱們把棧頂彈出,而後忽略他們。
而後最後剩下了 \(a_0, \cdots, a_{k - 1}\) 其中每一個 \(a_i\) 都說 \(a_{i + 1}\) 是誠實的,那麼顯然 \(a_{k - 1}\) 必定是誠實的。爲何呢?由於其中必定有我的是老實人,那麼在它後面的全部人必定都是老實人,那麼最後一我的必是老實人。
而後咱們就能夠在穩定的 \(2n\) 次裏問出全部人的類別啦。(好妙啊~)
放個瞎JB亂搞。
有一個容量爲 \(L\) 的水庫,天天晚上能夠聽任意體積的水。天天早上會有必定溫度和體積的水流入水庫,且要保證流入水以後水的整體積不能超過 \(L\) 。令體積分別爲 \(V_1,V_2\) ,溫度分別爲 \(t_1,t_2\) 的水混合後的溫度爲 \(\displaystyle \frac {V_1 * t_1 + V_2 * t_2} {V_1 + V_2}\) 。初始水庫爲空。現給出 \(n\) 天流入水的體積和溫度,分別最大化每一天中午水庫滿容量時的水溫。
\(1 \le n \le 5 \times 10^5\)
一道頗有意思的題~
咱們能夠發現兩個性質:
咱們利用一個單調隊列(隊列中的元素隊首到隊尾按 \(t\) 單調遞增),每次當前體積 \(>L\) 咱們不斷彈掉隊首,使得體積變小。而後隊尾溫度比隊尾前一個低,咱們就合併,直至不能合併便可。
至於爲何是對的呢?你能夠考慮把每一個水看作一個向量,咱們至關於看向量和的斜率,咱們其實就是須要貪心地維護一個下凸殼,本質上是同樣的。
有 \(n\) 個盒子,每一個盒子裏面有兩個球,分別寫了一個數字 \(x_i, y_i\) 。如今須要把每一個盒子其中的一個球染成紅色,另一個染成藍色。
令 \(R_{\max}\) 爲紅球數字最大值,其餘的同理,求 \((R_{\max} - R_{\min})(B_{\max} - B_{\min})\) 的最小值。
\(n \le 2 \times 10^5\)
腦子是個好東西,我也想要一個QAQ
令全局 \(x_i, y_i\) 最大值爲 \(A_{\max}\) ,最小值爲 \(A_{\min}\) 。顯然 \(R_{\max}, B_\max\) 其中一個須要取到 \(A_\max\) ,\(\min\) 同理。
咱們考慮分兩種狀況討論。
最大值和最小值被兩邊分別取到了。
不妨令 \(R_\max = A_\max, B_\min = A_\min\) ,那麼咱們顯然須要最小化 \(B_\max\) ,最大化 \(R_\min\) 。
那麼顯然對於每一個盒子,咱們把較小的那個給 \(B\) ,較大的給 \(R\) ,顯然是最優的。
最大值和最小值都給一邊取到了。
不妨令 \(R_\max = A_\max, R_\min = A_\min\) ,那麼咱們就須要最小化 \(B_\max - B_\min\) 。
咱們考慮從小到大枚舉 \(B_\min\) ,而後動態維護 \(B_\max\) 的最小值。
若是當且 \(B_\min = A_\min\) ,咱們顯然 \(B_\max\) 取到全部的 \(\min\{x_i, y_i\}\) 的最大值是最優的。
而後咱們每次把 \(B_\min\) 變大,也就是翻轉 \(B_\min\) 的顏色,隨便維護一下最值便可。
\(\mathcal O(n \log n)\)
一個長爲 \(n\) 的數軸,一開始上面有兩個盒子在 \(A, B\) ,有 \(q\) 次要求,每次給出一個座標 \(x_i\) ,須要把其中一個盒子移到 \(x_i\) ,問最少移動的距離和。
\(1 \le n, q \le 2 \times 10^5\)
惟一一道本身作出來的 \(F\) TAT
雖然很水。
假設當前處理第 \(p\) 個要求。考慮 \(dp\) ,設 \(f_{i, j}\) 爲當前兩個盒子分別在 \(i, j\) 的最少距離和,轉移顯然。
但顯然每次咱們有個盒子的位置必定在 \(x_{p - 1}\) ,咱們只須要記 \(f_i\) 爲其中一個盒子在 \(x_{p - 1}\) ,另一個在 \(i\) 的最少距離和。
顯然一次咱們不會同時移動兩個盒子,這樣必定不優。
直接實現是 \(\mathcal O(n^2)\) 的,對於第一個轉移就是全局加,對於第二個轉移拆絕對值,而後維護 \(f_i \pm i\) 的最小值便可。
均可以用線段樹實現 \(\mathcal O(n \log n)\) 。
定義 $rev(n) $ 爲將 \(n\) 的十進制位翻轉的結果,例如 \(rev(123) = 321, rev(4000) = 4\) 。
給定正整數 \(D\) ,求有多少個 \(N\) 知足 \(rev(N) = N + D\) 。
\(1 \le D < 10^9\)
考慮固定長度爲 \(L + 1\) ,假設從低到高每一位分別是 \(b_i\) ,那麼其實就是
\[ \begin{aligned} rev(N ) - N &= \sum_{i = 0}^{L} (10^{L - i} - 10^i) b_i\\ &= \sum_{i = 0}^{\lfloor \frac L2\rfloor} (10^{L - i} - 10^i) (b_i - b_{L - i}) \end{aligned} \]
咱們等價求把 \(0 \sim \lfloor \frac L2\rfloor\) 的每一個 \(v_i = 10^{L - i} - 10^i\) 乘上 \(-9 \sim 9\) 和爲 \(D\) 的方案數。(對於每一個 \(-9 \sim 9\) 對應了兩個數的一種組合)。
直接 \(dfs\) 可能會 TLE
,考慮利用性質優化,咱們觀察到:
\[ v_i > \sum_{j = i + 1}^{\lfloor \frac L2\rfloor} 9 v_j \]
那麼意味着若是咱們肯定前 \(i\) 位,組合出來的數與 \(D\) 相差 \(v_i\) 時,顯然是之後不管如何也沒法恢復的。
那麼每一步其實咱們的填法從 \(18\) 下降到只有 \(2\) 種了。
咱們須要枚舉的長度應該是 \(L_D \sim 2L_D\) ( \(L_D\) 爲 \(D\) 十進制的長度),由於咱們加減的範圍應該是恰好 \(L_D\) 的,超過 \(2L_D\) 加減最小數已經超過了 \(D\) 顯然沒法獲得。
有科學的複雜度爲
\[ \begin{aligned} \mathcal O(\sum_{i = L_D}^{2L_D} 2^{\lfloor \frac i 2\rfloor}) &= \mathcal O(2^{L_D}) = \mathcal O(2^{\log_{10} D})\\ &= \mathcal O(2^{\frac{\log_2 D}{\log_2{10}}}) = \mathcal O(D^{\log_{10} 2}) \approx \mathcal O(D^{0.3010}) \end{aligned} \]
跑的挺快的。
#include <bits/stdc++.h> #define For(i, l, r) for (register int i = (l), i##end = (int)(r); i <= i##end; ++i) #define Fordown(i, r, l) for (register int i = (r), i##end = (int)(l); i >= i##end; --i) #define Rep(i, r) for (register int i = (0), i##end = (int)(r); i < i##end; ++i) #define Set(a, v) memset(a, v, sizeof(a)) #define Cpy(a, b) memcpy(a, b, sizeof(a)) #define debug(x) cout << #x << ": " << (x) << endl using namespace std; typedef long long ll; template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; } template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; } inline int read() { int x(0), sgn(1); char ch(getchar()); for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1; for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48); return x * sgn; } void File() { #ifdef zjp_shadow freopen ("F.in", "r", stdin); freopen ("F.out", "w", stdout); #endif } int D, len, up; ll Pow[20], v[20]; int Pool[20], *d = Pool + 10; ll Dfs(ll cur, int dep) { if (dep == up) return !cur; int t = cur / v[dep]; ll res = 0; For (i, t - 1, t + 1) if (abs(i) <= 9 && abs(cur - i * v[dep]) < v[dep]) res += (d[i] - (i >= 0 && !dep)) * Dfs(cur - i * v[dep], dep + 1); return res; } int main () { File(); for (int tmp = (D = read()); tmp; tmp /= 10) ++ len; Pow[0] = 1; For (i, 1, 18) Pow[i] = 10ll * Pow[i - 1]; Rep (i, 10) Rep (j, 10) ++ d[i - j]; ll ans = 0; For (i, len, len << 1) { For (j, 0, up = i >> 1) v[j] = Pow[i - j - 1] - Pow[j]; ans += (i & 1 ? d[0] : 1) * Dfs(D, 0); } printf ("%lld\n", ans); return 0; }
### 題意
給你一個 \(n\) 個點的有向環套樹,須要對於每一個點定取值 \(a_i \ge 0\) ,知足。
問是否存在一種合法方案。
\(2 \le n \le 2 \times 10^5\)
其實操做本質上其實就是個 \(\mathrm{mex}\) ,對於樹上的 \(\mathrm{mex}\) ,每一個節點的值應該是肯定的。
須要考慮環,處理完全部環上節點的子樹,就得出了每一個環上節點的取值下界 \(b_i\) 。
全部 \(b_i\) 相同且環長度爲偶數:咱們隔一個數就把當前數加 \(1\) 便可。
全部 \(b_i\) 相同且環長度爲奇數:那麼隔一加一的就不行了,其實不難發現這樣沒法構造出合法方案。
存在有 \(b_i\) 不一樣:找到 \(b_i\) 最小的點 \(v\) 把它 \(+1\) ,而後依次考慮 \(u \to v\) 而後若是 \(b_u = b_v + 1\) 那麼咱們繼續操做便可,不難發現這樣操做必定會在某點中止不會繞圈。
這樣咱們就在 \(\mathcal O(n)\) 的時間內判斷出來了。