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$

可以用树状数组做二维偏序

#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;
}
[USACO11FEB]Generic Cow Protests G

 

posted @ 2020-09-12 17:29  QDK_Storm  阅读(174)  评论(0编辑  收藏  举报