【USACO】奶牛抗议 树状数组+dp

题目描述

约翰家的 N 头奶牛正在排队游行抗议。一些奶牛情绪激动,约翰测算下来,排在第 i 位的奶牛
的理智度为 A i ,数字可正可负。
约翰希望奶牛在抗议时保持理性,为此,他打算将这条队伍分割成几个小组,每个抗议小组的理
智度之和必须大于或等于零。奶牛的队伍已经固定了前后顺序,所以不能交换它们的位置,所以分在
一个小组里的奶牛必须是连续位置的。除此之外,分组多少组,每组分多少奶牛,都没有限制。
约翰想知道有多少种分组的方案,由于答案可能很大,只要输出答案除以 1000000009 的余数即
可。

输入

• 第一行:单个整数 N,1 ≤ N ≤ 100000
• 第二行到第 N + 1 行:第 i + 1 行有一个整数 A i ,−10 5 ≤ A i ≤ 10 5

输出

• 单个整数:表示分组方案数模 1000000009 的余数

 

样例输入

4 2 3 -3 1

样例输出

4

提示

如果分两组,可以把前三头分在一组,或把

后三头分在一组;如果分三组,可以把中间两头

分在一组,第一和最后一头奶牛自成一组;最后

一种分法是把四头奶牛分在同一组里。
 
 
题解:
朴素做法 if(sum[i]-sum[j]>=0)f[i]+=f[j].
于是发现只要sum[j]<=sum[i] 即可转移
然后以sum[i]为下标,维护树状数组即可,没事可以离散化一下.
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 typedef long long ll;
 7 const int mod=1000000009,N=100005;
 8 int gi(){
 9     int str=0,f=1;char ch=getchar();
10     while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
11     while(ch>='0' && ch<='9')str=str*10+ch-48,ch=getchar();
12     return str*f;
13 }
14 int a[N],id[N],n;ll Tree[N*4],sum[N],b[N],f[N];
15 int pf(ll x)
16 {
17     int l=1,r=n,mid;
18     while(l<=r)
19     {
20         mid=(l+r)>>1;
21         if(b[mid]==x)return mid;
22         if(x>b[mid])l=mid+1;
23         else r=mid-1;
24     }
25     return 0;
26 }
27 void add(int sta,ll x){for(int i=sta;i<=n;i+=(i&(-i)))Tree[i]+=x,Tree[i]%=mod;}
28 ll getsum(int sta)
29 {
30     ll sum=0;
31     for(int i=sta;i>=1;i-=(i&(-i)))sum+=Tree[i],sum%=mod;
32     return sum;
33 }
34 int main()
35 {
36     n=gi();
37     for(int i=1;i<=n;i++)a[i]=gi(),sum[i]=sum[i-1]+a[i],b[i]=sum[i];
38     sort(b+1,b+n+1);
39     for(int i=1;i<=n;i++)
40     {
41         id[i]=pf(sum[i]);
42     }
43     for(int i=1;i<=n;i++)
44     {
45         f[i]=getsum(id[i]);
46         if(sum[i]>=0)f[i]++;
47         f[i]%=mod;
48         add(id[i],f[i]);
49     }
50     printf("%lld",f[n]%mod);
51     return 0;
52 }

 

 

posted @ 2017-06-20 13:25  PIPIBoss  阅读(272)  评论(0编辑  收藏  举报