奶牛抗议 DP 树状数组

奶牛抗议 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;
}

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

时间: 2024-08-11 07:49:45

奶牛抗议 DP 树状数组的相关文章

bzoj 1669: [Usaco2006 Oct]Hungry Cows饥饿的奶牛【dp+树状数组+hash】

最长上升子序列.虽然数据可以直接n方但是另写了个nlogn的 转移:f[i]=max(f[j]+1)(a[j]<a[i]) O(n^2) #include<iostream> #include<cstdio> using namespace std; const int N=5005; int n,a[N],f[N],ans; int read() { int r=0,f=1; char p=getchar(); while(p>'9'||p<'0') { if(

HDU 2227 Find the nondecreasing subsequences (DP+树状数组+离散化)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2227 Find the nondecreasing subsequences                                  Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)                                             

树形DP+树状数组 HDU 5877 Weak Pair

1 //树形DP+树状数组 HDU 5877 Weak Pair 2 // 思路:用树状数组每次加k/a[i],每个节点ans+=Sum(a[i]) 表示每次加大于等于a[i]的值 3 // 这道题要离散化 4 5 #include <bits/stdc++.h> 6 using namespace std; 7 #define LL long long 8 typedef pair<int,int> pii; 9 const double inf = 12345678901234

poj 3616 Milking Time dp+树状数组

题意: 给一堆区间,每个区间有开始时间s,结束时间e,和收益w,现在要找一些区间使收益和最大,且区间之间的间隔最小为r. 分析: 这道题用dp做是简单题,用dp+树状数组做是中等题.dp问题的关键是对状态的定义.有两种方法,一:dp[k]表示按开始时间排序到第k个区间能取得的最大收益.二:dp[t]表示在时间t时能获得的最大收益.定义好状态方程就好写了这不再赘述.有趣的是这个时间复杂度.设一共有M个区间,所有区间的最大时间为L,第一种是M^2的,第二种是M*(logL+logM)的,这题M才10

HDU 5542 The Battle of Chibi dp+树状数组

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5542 题意:给你n个数,求其中上升子序列长度为m的个数 可以考虑用dp[i][j]表示以a[i]结尾的长度为j的上升子序列有多少 裸的dp是o(n2m) 所以需要优化 我们可以发现dp的第3维是找比它小的数,那么就可以用树状数组来找 这样就可以降低复杂度 #include<iostream> #include<cstdio> #include<cstring> #include

第十四个目标(dp + 树状数组)

Problem 2236 第十四个目标 Accept: 17    Submit: 35 Time Limit: 1000 mSec    Memory Limit : 32768 KB  Problem Description 目暮警官.妃英里.阿笠博士等人接连遭到不明身份之人的暗算,柯南追踪伤害阿笠博士的凶手,根据几起案件现场留下的线索发现凶手按照扑克牌的顺序行凶.在经过一系列的推理后,柯南发现受害者的名字均包含扑克牌的数值,且扑克牌的大小是严格递增的,此外遇害者与毛利小五郎有关. 为了避免

HDU5293(SummerTrainingDay13-B Tree DP + 树状数组 + dfs序)

Tree chain problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1798    Accepted Submission(s): 585 Problem Description Coco has a tree, whose vertices are conveniently labeled by 1,2,-,n.The

Gym - 100269F Flight Boarding Optimization(dp+树状数组)

原题链接 题意: 现在有n个人,s个位置和你可以划分长k个区域你可以把s个位置划分成k个区域,这样每个人坐下你的代价是该区域内,在你之前比你小的人的数量问你怎么划分这s个位置(当然,每个区域必须是连续的),才能使得总代价最小,输出代价. 分析:dp[i][j]表示第i个位置是第j个区域的结尾,dp[i][j]→dp[t][j+1]暴力转移.但是需要预处理每个范围里的代价值,需要树状数组维护. #include<bits/stdc++.h> using namespace std; const

codeforces 597C C. Subsequences(dp+树状数组)

题目链接: C. Subsequences time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output For the given sequence with n different elements find the number of increasing subsequences with k + 1 elements. It is