給你一個數列S,一個該數列的連續和(Continuous Sum,以下簡稱CS)是指S當中的某些連續項之總和。 很容易算得出來,一個總長度為項的數列S,其連續和(CS)共有$\frac{n(n+1)}{2}$個。 注意,問題來囉! 請問,這$\frac{n(n+1)}{2}$個連續和(CS)之中,第k大的是多少?
$n\leq 20000, |a_i|\leq 10000$
二分搜+merge sort 複雜度 $O(nlognlogC), C=20000\times 10000\times 2$ 結果卻狂吃TLE 花了3個小時debug 丟了27筆submission 問了幾個電神 其中一個叫我注意二分搜 我原本範圍設l=-200000025, r=200000025
改成沒負數之後 他過了他過了 他過了 我好可撥
後來才想到 當$l=-1,\ r=0$時 $r=m$會無法更新 以後隨時提醒自己二分搜有負數時要特別小心@@
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 #include <bits/stdc++.h> using namespace std;vector<int > tmp; int num (int ans, int l, int r) { if (l>=r) return 0 ; int m = (l+r)/2 ; int cnt = num (ans, l, m)+num (ans, m+1 , r); int it = l; for (int i = m+1 ; i <= r; i++) { while (it<=m && tmp[i]-tmp[it]>ans) { it++; } cnt+=(m+1 )-it; } vector<int > www; int a=l, b=m+1 ; for (int i = 0 ; i < r-l+1 ; i++) { if (a>m || (b<=r &&tmp[b]<tmp[a])) { www.push_back (tmp[b]); b++; } else { www.push_back (tmp[a]); a++; } } for (int i = 0 ; i < r-l+1 ; i++) tmp[l+i]=www[i]; return cnt; } signed main () { ios::sync_with_stdio (0 ); cin.tie (NULL ); int n, k; while (cin >> n >> k) { if (!n) break ; vector<int > sum (n+1 ) ; for (int i = 1 ; i <= n; i++) { cin >> sum[i]; sum[i]+=sum[i-1 ]; } int l = 0 , r=400000050 ; int rk = ((n+1 )*n)/2 -k+1 ; while (l<r) { tmp=sum; int m = (l+r)/2 ; int cnt = num (m-200000025 , 0 , n); if (cnt < rk) l=m+1 ; else r=m; } cout << l-200000025 << '\n' ; } }