--- tags: CP --- # 每個人都需要一個機器貓朋友 > reference: NHDK Moon Festival Ten Point Round 2021 在 22 世紀,哆啦A夢是日本警視廳的警視總監,他奉命要調查在太平洋第7島鏈上面的勢力,進行武力分析。 哆啦A夢派出了小哆啦去調查島鏈上面的小島,共 $N$ 個小島,並且對每個小島進行武力分析,得知每個小島的武力值。 這些小島分成兩種派系,一派是支持大雄、一派是支持胖虎,哆啦A夢為了保護大雄避免胖虎的欺負,所以想先分析島鏈上有多少個區間,火拼時大雄會輸。 區間火拼: 則計算區間中大雄派的武力值總和與胖虎派武力值總和,若胖虎派武力值總和大於大雄派武力值總和則大雄派輸。 ![](https://i.imgur.com/D1ig2N5.png) 「我不在的時候你能夠好好照顧自己嗎?」哆啦 A夢邊生氣邊流淚地問大雄 # Input 只有一組資料 第一行為一個正整數 $N$ ($1 \leq N \leq 2 \cdot10^5$),代表島鏈上面的小島數量。 第二行共有 $N$ 個整數 $a_i$ ($1 \leq |a_i| \leq 10^5$),$|a_i|$為小島的武力值,當 $a_i > 0$ 則為大雄派 ,反之則為胖虎派。 # Output 輸出一個整數,代表島鏈上有多少個區間,火拼時大雄派會輸。 # Sample Input1: ``` 5 3 4 5 6 7 ``` Output1: ``` 0 ``` Input2: ``` 5 1021 -5009 1516 -8002 -6311 ``` Output2: ``` 13 ``` # 範例說明 在第一個範例中,小島都是支持大雄,所以大雄沒有輸。 在第二個範例中,共有13個區間大雄會輸,分別為: $[2, 2]$, $[4, 4]$, $[5, 5]$, $[1, 2]$ $[2, 3]$, $[3, 4]$, $[4, 5]$, $[1, 3]$ $[2, 4]$, $[3, 5]$, $[1, 4]$, $[2, 5]$, $[1, 5]$ 以區間 $[1, 4]$ 為例,支持大雄的武力為$1021+1516=2537$、支持胖虎的武力為$5009+8002=13011$,所以這個區間大雄輸。 # Hint :::spoiler 區間和可視為兩個前綴和相減。 ::: # 題解 :::spoiler 首先,本題目是在找 區間和$\leq 0$ 的個數,如果直接枚舉L與R,時間複雜度為 $O(N^3)$。 使用前綴和加速計算區間和,時間複雜度是 $O(N^2)$。 考慮到一個問題,區間和就是兩個前綴和相減,也就是尋找兩個前綴和,前面的前綴和大於後面的前綴和時,此對應的區間和就是$<0$,當我們將問題思考到這邊的時候,就完成了這題的要求。 前綴和的模反元素數量就是解。 ::: :::spoiler 解法1 ```cpp= #include <bits/stdc++.h> #define pb push_back #define Int long long using namespace std; Int invpair(vector<Int> &v, int l, int r) { if(l == r) return 0; int m = (l+r)/2; Int res = invpair(v, l, m) + invpair(v, m+1, r); vector<Int> tmp; for(int i = l, j = m+1; i <= m || j <= r; ) { if(i <= m && (j > r || v[i] <= v[j])) { tmp.pb(v[i++]); res += (j-m-1); } else tmp.pb(v[j++]); } for(auto it: tmp) v[l] = it, l++; return res; } void solve(){ int n; cin >> n; vector<Int> A(n), B{0}; for(auto& it: A) cin >> it; for(auto it: A) B.pb(B.back()+it); //len(B) == n+1 Int ans = invpair(B, 0, n); //[L, R] cout << ans << endl; } int main(){ ios::sync_with_stdio(0); cin.tie(0); int t=1; //cin >> t; while(t--) solve(); return 0; } ``` ::: :::spoiler 解法2 ```cpp= #include <bits/stdc++.h> #define pb push_back #define mp make_pair #define add insert #define Int long long #define pi acosl(-1) #define MEM(x) memset(x,0,sizeof(x)) #define x first #define y second using namespace std; struct BIT { vector<Int> A; int n; BIT(int _n) { n=_n; A.resize(n+1); } int lowbit(int idx) { return (idx&(-idx)); } void update(int idx, Int v) { for(int i = idx+1; i <= n; i += lowbit(i)) A[i] += v; } Int query(int idx) { Int res = 0; for(int i = idx+1; i; i -= lowbit(i)) res += A[i]; return res; } }; void solve(){ int n; cin >> n; vector<Int> A(n), B{0}, Buni; for(auto& it: A) cin >> it; for(auto it: A) B.pb(B.back() + it); Buni = B; sort(Buni.begin(), Buni.end()); Buni.erase(unique(Buni.begin(), Buni.end()), Buni.end()); //BIT BIT T1(Buni.size()); Int ans = 0; for(int i = 0; i < B.size(); i++) { int idx = lower_bound(Buni.begin(), Buni.end(), B[i]) - Buni.begin(); Int cnt = i - T1.query(idx); ans += cnt; T1.update(idx, 1LL); } cout << ans << endl; } int main(){ ios::sync_with_stdio(0); cin.tie(0); int t=1; //cin >> t; while(t--) solve(); return 0; } ``` :::