码迷,mamicode.com
首页 > 编程语言 > 详细

奶牛抗议 DP 树状数组

时间:2019-11-12 20:34:55      阅读:103      评论:0      收藏:0      [点我收藏+]

标签:math   name   初始   +=   方案   unique   维护   下标   lower   

奶牛抗议 DP 树状数组

USACO的题太猛了

容易想到\(DP\),设\(f[i]\)表示为在第\(i\)位时方案数,转移方程:
\[ f[i]=\sum f[j]\;(j< i,sum[i]-sum[j]\ge0) \]
\(O(n^2)\)过不了,考虑优化

移项得:
\[ f[i]=\sum f[j]\;(j< i,sum[i]\ge sum[j]) \]
这时候我们发现相当于求在\(i\)前面并且前缀和小于\(sum[i]\)的所有和,这就可以用一个树状数组优化了,在树状数组维护下标为\(sum[i]\)\(f[i]\)的前缀和。对于每个\(f[i]\)即为树状数组上\(sum[i]\)的前缀和。

这里需要注意的是前缀和可能为负,而树状数组下标不能为负,所以我们要离散化一下。

#include <cstdio>
#include <algorithm>
using namespace std;
#define MAXN 100010
#define lowbit(x) ((x)&(-(x)))
#define MOD 1000000009
int n,sum[MAXN],s;
int sum_sort[MAXN+1];
int tre[MAXN+1];
inline void add(int x, int val){
    while(x<=s){
        tre[x]=(tre[x]+val)%MOD;
        x+=lowbit(x);
    }
}
inline int get_sum(int x){
    int res=0;
    while(x>0){
        res=(res+tre[x])%MOD;
        x-=lowbit(x);
    }
    return res;
}
int main(){
    scanf("%d", &n);
    for(int i=1;i<=n;++i)
        scanf("%d", &sum[i]),sum[i]+=sum[i-1];
    for(int i=1;i<=n;++i) sum_sort[i]=sum[i];
    sort(sum_sort, sum_sort+1+n);
    s=unique(sum_sort, sum_sort+1+n)-sum_sort;
    for(int i=0;i<=n;++i) sum[i]=lower_bound(sum_sort, sum_sort+s, sum[i])-sum_sort+1;
    add(sum[0], 1); // f[0]=1 计数dp初始化
    int ans=0;
    for(int i=1;i<=n;++i){
        ans=get_sum(sum[i]); // 获得f[i]
        add(sum[i], ans); // 维护树状数组
    }
    printf("%d\n", ans);
    return 0;
}

奶牛抗议 DP 树状数组

标签:math   name   初始   +=   方案   unique   维护   下标   lower   

原文地址:https://www.cnblogs.com/santiego/p/11844590.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!