LG P2344 [USACO11FEB]Generic Cow Protests G
Description
Farmer John 的 $N$ 头奶牛($1 \leq N \leq 10^5$)排成一列,正在进行一场抗议活动。第 $i$ 头奶牛的理智度为 $a_i$($-10^4 \leq a_i \leq 10^4$)。
FJ 希望奶牛在抗议时保持理性,为此,他打算将所有的奶牛隔离成若干个小组,每个小组内的奶牛的理智度总和都要不小于零。
由于奶牛是按直线排列的,所以一个小组内的奶牛位置必须是连续的。请帮助 FJ 计算一下,满足条件的分组方案有多少种。
Solution
对于$n^2$做法,有转移方程
$$dp_i=\sum dp_j, \sum_{k=j+1}^i a_k \geq 0$$
即
$$dp_i=\sum dp_j, sum_i-sum_j \geq 0$$
考虑优化
对于上面的转移方程,$i$能从$j$转移来当且仅当
- $j < i$
- $sum_j \leq sum_i$
可以用树状数组做二维偏序
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<algorithm> #include<iostream> #include<cstdio> #include<map> using namespace std; long long n,sum[100005],tot,bit[100005],ans,a[100005]; const long long mod=1e9+9; map<long long,long long>mp; inline long long read() { long long f=1,w=0; char ch=0; while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { w=(w<<1)+(w<<3)+ch-'0'; ch=getchar(); } return f*w; } long long lowbit(long long x) { return x&-x; } long long add(long long p,long long v) { while(p<=n) { bit[p]+=v; p+=lowbit(p); } } long long query(long long p) { long long ret=0; while(p) { ret+=bit[p]; p-=lowbit(p); } return ret; } int main() { n=read(); for(long long i=1;i<=n;i++) { a[i]=sum[i]=sum[i-1]+read(); } sort(sum,sum+n+1); tot=unique(sum,sum+n+1)-sum-1; for(long long i=0;i<=tot;i++) { mp[sum[i]]=i+1; } add(mp[0],1); for(long long i=1;i<n;i++) { ans=query(mp[a[i]])%mod; add(mp[a[i]],ans); } printf("%lld\n",query(mp[a[n]])%mod); return 0; }