[USACO11FEB]Generic Cow Protests---線段樹優化

題目:[USACO11FEB]Generic Cow Protests


這道題首先想到DP。ios

考慮:階段數通常爲序列編號,若是咱們設第二維狀態用以表示劃分段數,空間複雜度不夠。綜上,咱們使用\(dp[i]\)直接表示第i位全部狀況和。數組

有方程:數據結構

\[dp[i]=\sum_{j=1}^{i-1}{dp[j]}(sum[i]-sum[j]≥0) \]

時間複雜度爲\(O(n^2)\)優化

實際上,咱們使用數據結構優化時間複雜度。考慮條件:spa

\[sum[i]-sum[j]≥0 \]

移項得:code

\[sum[i]≥sum[j] \]

也就是說,它的狀態值是全部小於\(sum[i]\)的位置,於是能夠使用樹狀數組或線段樹。string

具體地,咱們能夠將全部前綴和進行離散化,按照值域創建一顆線段樹,從\(1\)\(n\)一次統計答案。
時間複雜度爲\(O(nlogn)\)it

#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;
}
相關文章
相關標籤/搜索