题目大意就是说帮你给出一个序列a,让你求出它的非递减序列有多少个。

设dp[i]表示以a[i]结尾的非递减子序列的个数,由题意我们可以写出状态转移方程:

dp[i] = sum{dp[j] | 1<=j<i && a[j] <= a[i]} + 1.

这样一来这里面所有的dp[]值的和就是最后的结果。

但是这个状态转移方程很明显复杂度是O(n^2),但是n可以达到100000,很明显会超时。既然是求前导和,很明显我们就应该可以想到用树状数组(虽然我怎么也不可能想到==!),这样一来那么复杂度就可以降到O(nlogn)。

那么怎么求前导和呢??也并不是所有的dp[j](1<=j<i)都要被加进去啊,只有满足a[j]<=a[i]时dp值才可以被计算在内。。。

解决办法就是先将原数组复制一份,然后排序,然后再按照原顺序找出每一个数的排序后的所在位置,然后计算这个位置的dp[]值,可以通过一例看出他的正确性:

原数组:  8 5 3 4 1

排序后:  1 3 4 5 8

可以看出原数组的每一个数对应到排序后的下标就是:5 4 2 3 1

没有计算前,树状数组里的值全为0,然后

1、找到8的位置,并计算以‘8’结尾的dp[]的值,也就是计算‘8’在排序后所在位置5的值, 计算dp[5] = 0 + 1 = 1

2、然后找到‘5’在排序后的位置4,由于‘8’>‘5’,所以以‘5’结尾的dp值应该也是1,正好排序后‘5’在第4个,在‘8’前面,自然dp[4]计算出来还是1

3、同理,‘3’出现在第二个,dp[2] = 1

4、然后到‘4’,他在排序后出现在第3 个,而原数组中‘4’之前有一个数‘3’,所以计算出来以‘4’结尾的dp[]值应该就是以‘3’结尾的dp值+1等于2,而我们看排序后4出现在第3个,而第3个之前又正好有一个dp[2]=1已经被计算出来了,这样dp值的前导和就是1,从而dp[3] = dp[2] + 1 = 2.

5、最后dp[1] = 1.所以最后结果就是1+1+1+2+1 = 6

其实上面的排序找到下标就是为了保证每个数计算出来的值都是满足a[j] < a[i]时,所计算出来的dp值。这也就是原题的解。

而要实现找到原数组在排序后的位置,我们只需要二分查找就可以了,又因为原数组可能会有相同的数,为了找到的是同一个标号,所以需要二分查找下限(或者上限)。

 #include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; #define mem(a) memset(a,0,sizeof(a))
#define mod 1000000007
#define MAXN 100010 int num[MAXN], d[MAXN], N, DP[MAXN]; int lowbit(int x)
{
return x & -x;
} int getSum(int k)
{
int ans = ;
while(k>=)
{
ans = (ans + DP[k]) % mod;
k -= lowbit(k);
}
return ans;
} void edit(int k,int val)
{
while(k<=N)
{
DP[k] = (DP[k] + val) % mod;
k += lowbit(k);
}
} int bsearch(int num)
{
int x = , y = N+, mid;
while(y > x )
{
mid = (x+y)/;
if(d[mid] == num && d[mid-]<num) return mid;
if(d[mid] >= num) y = mid;
else x = mid+;
}
return mid;
} int main()
{
while(~scanf("%d", &N))
{
mem(DP);
mem(d); mem(num);
for(int i = ; i <= N; i ++)
{
scanf("%d", &num[i]);
d[i] = num[i];
}
sort(d+, d+N+);
for(int i=;i<=N;i++)
{
int id = bsearch(num[i]);
edit(id, getSum(id)+);
}
printf("%d\n", getSum(N));
}
return ;
}

HDU2227Find the nondecreasing subsequences(树状数组+DP)的更多相关文章

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

    题目链接:http://codeforces.com/contest/597/problem/C 给你n和数(1~n各不同),问你长为k+1的上升自序列有多少. dp[i][j] 表示末尾数字为i 长 ...

  2. CodeForces - 314C Sereja and Subsequences (树状数组+dp)

    Sereja has a sequence that consists of n positive integers, a1, a2, ..., an. First Sereja took a pie ...

  3. hdu 2227(树状数组+dp)

    Find the nondecreasing subsequences Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/3 ...

  4. hdu 3030 Increasing Speed Limits (离散化+树状数组+DP思想)

    Increasing Speed Limits Time Limit: 2000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java ...

  5. hdu 4991(树状数组+DP)

    Ordered Subsequence Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

  6. codeforces 597C (树状数组+DP)

    题目链接:http://codeforces.com/contest/597/problem/C 思路:dp[i][j]表示长度为i,以j结尾的上升子序列,则有dp[i][j]= ∑dp[i-1][k ...

  7. hdu 4622 Reincarnation trie树+树状数组/dp

    题意:给你一个字符串和m个询问,问你l,r这个区间内出现过多少字串. 连接:http://acm.hdu.edu.cn/showproblem.php?pid=4622 网上也有用后缀数组搞得. 思路 ...

  8. HDU 6348 序列计数 (树状数组 + DP)

    序列计数 Time Limit: 4500/4000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Subm ...

  9. [Codeforces261D]Maxim and Increasing Subsequence——树状数组+DP

    题目链接: Codeforces261D 题目大意:$k$次询问,每次给出一个长度为$n$的序列$b$及$b$中的最大值$maxb$,构造出序列$a$为$t$个序列$b$连接而成,求$a$的最长上升子 ...

随机推荐

  1. iOS 开发 中级:UIToolbar,UINavigationBar,UITabBar,UIBarButtonItem,UITabBarItem自定义方法总结

    原文:  http://blog.csdn.net/songrotek/article/details/8692866?utm_source=tuicool 对于UIToolbar,UINavigat ...

  2. 【第八篇】mvc razor视图配置404 500页面

    记住是最外层的这个Web.config 在  <system.web> </system.web>节点里面配置 <customErrors defaultRedirect ...

  3. Strlen()与sizeof()

    在学习C语言时以及面试中,经常会见到strlen()与sizeof()这一对容易混淆的概念,搞清楚这两个概念,往往考察了编程人员对语言的基本掌握能力. 首先大家先明确两个概念是: 1.strlen() ...

  4. WEBUS2.0 In Action - 索引操作指南(2)

    上一篇:WEBUS2.0 In Action - 索引操作指南(1) | 下一篇:WEBUS2.0 In Action - 搜索操作指南(1) 3. 添加.删除.撤销删除和修改文档 在WEBUS中要将 ...

  5. Linux C double linked for any data type

    /************************************************************************** * Linux C double linked ...

  6. (转)每天一个Linux命令(4): mkdir

    http://www.cnblogs.com/peida/archive/2012/10/25/2738271.html linux mkdir 命令用来创建指定的名称的目录,要求创建目录的用户在当前 ...

  7. (六) 6.1 Neurons Networks Representation

    面对复杂的非线性可分的样本是,使用浅层分类器如Logistic等需要对样本进行复杂的映射,使得样本在映射后的空间是线性可分的,但在原始空间,分类边界可能是复杂的曲线.比如下图的样本只是在2维情形下的示 ...

  8. 【转】Android Interface的使用

    原文网址:http://www.3g-edu.org/Android_free/art115.htm Android应用程序采用Java语言编写,Java语法和C/C++有很大的相似性,但也有一些特别 ...

  9. 身份证上的X到底代表什么?

    生活中,无论你是坐火车,还是办理各种手续,都需要用到身份证,它现在已经俨然成为我们生活的非常重要的一部分,但是关于身份证本身,你了解多少呢? 有人会说了,为什么我的身份证上写的有效时间是10年,而一些 ...

  10. web-3g-(163)网易-邮箱-记事本-数据库设计

    ylbtech-DatabaseDesgin:ylbtech-cnblogs(博客园)-数据库设计-2,Admin(用户后台) DatabaseName:cnblogs(博客园) Model:Admi ...