奶牛抗议

题目描述

约翰家的 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;
}

 

转载于:https://www.cnblogs.com/Y-E-T-I/p/7050869.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值