题目描述
约翰家的 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
提示
如果分两组,可以把前三头分在一组,或把
后三头分在一组;如果分三组,可以把中间两头
分在一组,第一和最后一头奶牛自成一组;最后
一种分法是把四头奶牛分在同一组里。
题解:
动态规划+树状数组+离散化
不难列出
f[i]=sum(f[j]|sum[i]-sum[j]>0)
sum[i]-sum[j]>0→sum[i]>sum[j]
转化为求sum[j]小于sum[i]的f[j]的和
f[i]=sum(f[j]|sum[i]>sum[j])
是不是很眼熟?
树状数组存小于x的f的和
则f[i]=getsum(sum[i]);
add(sum[i],f[i])即可.
由于sum值太大,要用离散化。
据yzd大佬说:此题可以不用离散,大致是按sum排序
f[i]=getsum(i);
add(i,f[i]);
没有代码实现,读者可以自己思考一下。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int d[1000005],f[100005],n,sum[100005],p[100005],maxx; int lowbit(int x) { return x&(-x); } void add(int x,int c) { while (x<=1000000) { d[x]+=c; d[x]%=1000000009; x+=lowbit(x); } } int query(int x) { int s=0; while (x>0) { s+=d[x]; s%=1000000009; x-=lowbit(x); } return s%1000000009; } int binary(int x) { int l=1,r=n+1; while (l<r) { int mid=(l+r)/2; //if (p[mid]==x) return l; if (p[mid]>=x) r=mid; else l=mid+1; } return l; } int main() {int i; //freopen("file.in","r",stdin); scanf("%d",&n); for (i=1;i<=n;i++) { scanf("%d",&sum[i]); sum[i]+=sum[i-1]; p[i]=sum[i]; } p[n+1]=0; sort(p+1,p+n+2); // for (i=1;i<=n;i++) // sum[i]=binary(sum[i]); add(binary(0),1); for (i=1;i<=n;i++) { f[i]=query(binary(sum[i])); f[i]%=1000000009; add(binary(sum[i]),f[i]); } cout<<f[n]%1000000009; }