BZOJ 2274 [Usaco2011]Generic Cow Protests

BZOJ_2274

    这个题目不难得到dp的递推方程,f[i]=sum{f[j](A[i]-A[j]>=0)},但是如果裸着做显然是O(N^2)的复杂度,但如果我们把每次计算的f[i]依A[i]的值的大小存到对应的位置时,每次就可以O(logN)求得sum{f[j](A[i]-A[j]>=0)}了。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXD 100010
#define MOD 1000000009
int N, S, a[MAXD], A[MAXD], sum[MAXD];
void init()
{
    A[0] = 0;
    for(int i = 1; i <= N; i ++)
        scanf("%d", &a[i]), A[i] = A[i - 1] + a[i];
    std::sort(A, A + N + 1);
    S = std::unique(A, A + N + 1) - A;
}
void insert(int x, int v)
{
    for(int i = x; i <= S; i += i & -i) sum[i] = (sum[i] + v) % MOD;
}
int query(int x)
{
    int ans = 0;
    for(int i = x; i > 0; i -= i & -i) ans = (ans + sum[i]) % MOD;
    return ans;
}
int BS(int x)
{
    return std::lower_bound(A, A + S, x) - A;
}
void solve()
{
    int s = 0, x, ans;
    memset(sum, 0, sizeof(sum[0]) * (S + 1));
    insert(BS(0) + 1, 1);
    for(int i = 1; i <= N; i ++)
    {
        s += a[i];
        x = BS(s) + 1;
        ans = query(x);
        insert(x, ans);
    }
    printf("%d\n", ans);
}
int main()
{
    while(scanf("%d", &N) == 1)
    {
        init();
        solve();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/staginner/p/2709128.html