[USACO11FEB]Generic Cow Protests---線段樹優化
阿新 • • 發佈:2020-10-11
題目:[USACO11FEB]Generic Cow Protests
這道題首先想到DP。
考慮:階段數一般為序列編號,如果我們設第二維狀態用以表示劃分段數,空間複雜度不夠。綜上,我們使用\(dp[i]\)直接表示第i位所有情況和。
有方程:
\[dp[i]=\sum_{j=1}^{i-1}{dp[j]}(sum[i]-sum[j]≥0) \]時間複雜度為\(O(n^2)\)。
實際上,我們使用資料結構優化時間複雜度。考慮條件:
\[sum[i]-sum[j]≥0 \]移項得:
\[sum[i]≥sum[j] \]也就是說,它的狀態值是所有小於\(sum[i]\)的位置,因而可以使用樹狀陣列或線段樹。
具體地,我們可以將所有字首和進行離散化,按照值域建立一顆線段樹,從\(1\)到\(n\)一次統計答案。
時間複雜度為\(O(nlogn)\)
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> using namespace std; const int SIZE = 100000 + 10, mod = 1e9 + 9; int n, tot = 0, a[SIZE], b[SIZE], table[SIZE], s[SIZE], c[SIZE], dp[SIZE] = {}; int lowbit(int x) { return x & (-x); } void discrete() { sort(b, b + n + 1); table[++ tot] = b[0]; for(int i = 1; i <= n; ++ i) if(b[i] != b[i - 1]) table[++ tot] = b[i]; return; } int query(int v) { int L = 1, R = tot, mid; while(L < R) { mid = L + R >> 1; if(table[mid] < v) L = mid + 1; else R = mid; } return L; } void add(int x, int v) { while(x <= n) { c[x] = (c[x] + v) % mod; x += lowbit(x); } return; } int ask(int x) { int res = 0; while(x) { res = (res + c[x]) % mod; x -= lowbit(x); } return res; } int main() { scanf("%d", &n); memset(a, 0, sizeof(a)); memset(s, 0, sizeof(s)); for(int i = 1; i <= n; ++ i) { scanf("%d", &a[i]); s[i] = s[i - 1] + a[i]; } for(int i = 0; i <= n; ++ i) b[i] = s[i]; discrete(); add(query(0), 1); for(int i = 1; i <= n; ++ i) { int p = query(s[i]); dp[i] = ask(p); add(p, dp[i]); } printf("%d\n", dp[n]); return 0; }