奶牛抗议 DP 树状数组
USACO的题太猛了
容易想到(DP),设(f[i])表示为在第(i)位时方案数,转移方程:
[f[i]=sum f[j];(j< i,sum[i]-sum[j]ge0)
]
(O(n^2))过不了,考虑优化
移项得:
[f[i]=sum f[j];(j< i,sum[i]ge sum[j])
]
这时候我们发现相当于求在(i)前面并且前缀和小于(sum[i])的所有和,这就可以用一个树状数组优化了,在树状数组维护下标为(sum[i]),(f[i])的前缀和。对于每个(f[i])即为树状数组上(sum[i])的前缀和。
这里需要注意的是前缀和可能为负,而树状数组下标不能为负,所以我们要离散化一下。
#include <cstdio>
#include <algorithm>
using namespace std;
#define MAXN 100010
#define lowbit(x) ((x)&(-(x)))
#define MOD 1000000009
int n,sum[MAXN],s;
int sum_sort[MAXN+1];
int tre[MAXN+1];
inline void add(int x, int val){
while(x<=s){
tre[x]=(tre[x]+val)%MOD;
x+=lowbit(x);
}
}
inline int get_sum(int x){
int res=0;
while(x>0){
res=(res+tre[x])%MOD;
x-=lowbit(x);
}
return res;
}
int main(){
scanf("%d", &n);
for(int i=1;i<=n;++i)
scanf("%d", &sum[i]),sum[i]+=sum[i-1];
for(int i=1;i<=n;++i) sum_sort[i]=sum[i];
sort(sum_sort, sum_sort+1+n);
s=unique(sum_sort, sum_sort+1+n)-sum_sort;
for(int i=0;i<=n;++i) sum[i]=lower_bound(sum_sort, sum_sort+s, sum[i])-sum_sort+1;
add(sum[0], 1); // f[0]=1 计数dp初始化
int ans=0;
for(int i=1;i<=n;++i){
ans=get_sum(sum[i]); // 获得f[i]
add(sum[i], ans); // 维护树状数组
}
printf("%d
", ans);
return 0;
}