Description

How many nondecreasing subsequences can you find in the sequence S = {s1, s2, s3, ...., sn} ? For example, we assume that S = {1, 2, 3}, and you can find seven nondecreasing subsequences, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}.
 

Input

The input consists of multiple test cases. Each case begins with a line containing a positive integer n that is the length of the sequence S, the next line contains n integers {s1, s2, s3, ...., sn}, 1 <= n <= 100000, 0 <= si <= 2^31.
 

Output

For each test case, output one line containing the number of nondecreasing subsequences you can find from the sequence S, the answer should % 1000000007.
 

Sample Input

3
1 2 3
 

Sample Output

7

这个题目要求的是上升子序列的个数。

若设sum[i]表示以i为最后一个数的上升子序列的个数。

首先可以得到的是sum[i] = 1 + ∑(sum[j]) (a[j] <= a[i])。(ps:加1是因为子序列可以只包含一个数)

但是遍历sum[j]这个操作的时间需要O(n),所以要对这个操作进行优化。

很容易想到的是区间和,但是这个操作只需要求在i之前比a[i]小的那些点的和。

于是可以先把所有点的值初始化为0,然后从值最小的那个数开始求解,这样在求小的数的时候,大的数对应的值是0,这样的话大的数的贡献就是0,相当于没有加入计算。

举例说明:

对于序列5 1 3 2 4

先求1这个数,那么sum[1]就是[1, 2]区间内val[i]的和加1,即0+1。此时val[1]更新为1,sum[1]为1。

再求2这个数,那么sum[2]就是[1, 4]区间内val[i]的和加1,即1+1。此时val[2]更新为2,sum[2]为2。

再求3这个数,那么sum[3]就是[1, 3]区间内val[i]的和加1,即1+1。此时val[3]更新为2,sum[3]为2。

再求4这个数,那么sum[4]就是[1, 5]区间内val[i]的和加1,即1+2+2+1。此时val[4]更新为5,sum[4]为6。

最后求5这个数,那么sum[5]就是[1, 1]区间内val[i]的和加1,即0+1。此时val[5]更新为1,sum[5]为1。

所以答案就是sum[i]的和,就是12。

由于可以边求边加,所以sum数组可以省去。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define LL long long
#define N 1000000007 using namespace std; //线段树
//区间每点增值,求区间和
const int maxn = 100005;
struct node
{
int lt, rt;
int val;
}tree[4*maxn]; //向上更新
void PushUp(int id)
{
tree[id].val = (tree[id<<1].val + tree[id<<1|1].val)%N;
} //建立线段树
void Build(int lt, int rt, int id)
{
tree[id].lt = lt;
tree[id].rt = rt;
tree[id].val = 0;//每段的初值,根据题目要求
if (lt == rt)
{
//tree[id].val = 1;
return;
}
int mid = (lt + rt) >> 1;
Build(lt, mid, id<<1);
Build(mid+1, rt, id<<1|1);
//PushUp(id);
} //增加区间内每个点固定的值
void Add(int lt, int rt, int id, int pls)
{
if (lt <= tree[id].lt && rt >= tree[id].rt)
{
tree[id].val += pls * (tree[id].rt-tree[id].lt+1);
tree[id].val %= N;
return;
}
int mid = (tree[id].lt + tree[id].rt) >> 1;
if (lt <= mid)
Add(lt, rt, id<<1, pls);
if (rt > mid)
Add(lt, rt, id<<1|1, pls);
PushUp(id);
} //查询某段区间内的he
LL Query(int lt, int rt, int id)
{
if (lt <= tree[id].lt && rt >= tree[id].rt)
return tree[id].val;
int mid = (tree[id].lt + tree[id].rt) >> 1;
LL ans = 0;
if (lt <= mid)
ans += Query(lt, rt, id<<1);
if (rt > mid)
ans += Query(lt, rt, id<<1|1);
return ans%N;
} struct node1
{
LL val;
int id;
}p[100005]; bool cmp(node1 a, node1 b)
{
if (a.val != b.val)
return a.val < b.val;
else
return a.id < b.id;
} int n, len;
int sum;
LL ans; int main()
{
//freopen("test.in", "r", stdin);
while (scanf("%d", &n) != EOF)
{
for (int i = 0; i < n; ++i)
{
p[i].id = i+1;
scanf("%I64d", &p[i].val);
}
sort(p, p+n, cmp);
ans = 0;
Build(1, n, 1);
for (int i = 0; i < n; ++i)
{
sum = Query(1, p[i].id, 1)+1;
Add(p[i].id, p[i].id, 1, sum);
ans += sum;
ans %= N;
}
printf("%I64d\n", ans);
}
return 0;
}

ACM学习历程——HDU2227 Find the nondecreasing subsequences(线段树 && dp)的更多相关文章

  1. ACM学习历程—HDU5475 An easy problem(线段树)(2015上海网赛08题)

    Problem Description One day, a useless calculator was being built by Kuros. Let's assume that number ...

  2. ACM学习历程——NOJ1113 Game I(贪心 || 线段树)

    Description 尼克发明了这样一个游戏:在一个坐标轴上,有一些圆,这些圆的圆心都在x轴上,现在给定一个x轴上的点,保证该点没有在这些圆内(以及圆上),尼克可以以这个点为圆心做任意大小的圆,他想 ...

  3. ACM学习历程—Hihocoder 1289 403 Forbidden(字典树 || (离线 && 排序 && 染色))

    http://hihocoder.com/problemset/problem/1289 这题是这次微软笔试的第二题,过的人比第三题少一点,这题一眼看过去就是字符串匹配问题,应该可以使用字典树解决.不 ...

  4. ACM学习历程—CodeForces 176B Word Cut(字符串匹配 && dp && 递推)

    Description Let's consider one interesting word game. In this game you should transform one word int ...

  5. ACM学习历程—HDU5696 区间的价值(分治 && RMQ && 线段树 && 动态规划)

    http://acm.hdu.edu.cn/showproblem.php?pid=5696 这是这次百度之星初赛2B的第一题,但是由于正好打省赛,于是便错过了.加上2A的时候差了一题,当时有思路,但 ...

  6. HDU 4911 http://acm.hdu.edu.cn/showproblem.php?pid=4911(线段树求逆序对)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4911 解题报告: 给出一个长度为n的序列,然后给出一个k,要你求最多做k次相邻的数字交换后,逆序数最少 ...

  7. 完成了C++作业,本博客现在开始全面记录acm学习历程,真正的acm之路,现在开始

    以下以目前遇到题目开始记录,按发布时间排序 ACM之递推递归 ACM之数学题 拓扑排序 ACM之最短路径做题笔记与记录 STL学习笔记不(定期更新) 八皇后问题解题报告

  8. ACM学习历程—HDU 5512 Pagodas(数学)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5512 学习菊苣的博客,只粘链接,不粘题目描述了. 题目大意就是给了初始的集合{a, b},然后取集合里 ...

  9. ACM学习历程—HDU5521 Meeting(图论)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5521 学习菊苣的博客,只粘链接,不粘题目描述了. 题目大意就是一个人从1开始走,一个人从n开始走.让最 ...

随机推荐

  1. 2个YUV视频拼接技术

    http://blog.csdn.net/huahuahailang/article/details/9040847 2个YUV视频拼接技术 http://zhongcong386.blog.163. ...

  2. java代码评审内容

    评审内容 u 工具检查 □  Eclipse警告 □  FindBug □  CheckStyle □  Jupiter □  Subclipse 或者Subversive u 代码注释内容(详细参考 ...

  3. WinForm程序打包工具InnoSetup使用说明图文教程

    WinForm程序打包工具InnoSetup使用说明图文教程 WinForm程序开发测试好了,如果将Debug/Release里面的文件发给客户使用,会让客户觉得你不够专业,但是使用VS自带的打包工具 ...

  4. 调整图像的尺寸 - cvResize() 函数实现

    前言 有时会碰到一张图片太大了,想将它缩小.本文将讲解一个很好用的函数解决这个问题. 图像尺寸调整函数 cvResize() // 图像尺寸调整函数 void Resize ( const CvArr ...

  5. java中的 equals + hashCode

    [0]README 0.1)本文转自 core java volume 1, 旨在理清 equals + hashCode方法: [1]equals方法 1.1) Object中的 equals 方法 ...

  6. 【Android】第三方库使用的问题集

    Google/百度地图Key的获取 百度地图UnsatisfiedLinkError错误 async-http-client中的FATAL EXCEPTION Google/百度地图Key的获取 无论 ...

  7. Android 异常解决方法【汇总】

    (1)异常:Android中引入第三方Jar包的方法(Java.lang.NoClassDefFoundError解决办法) 1.在工程下新建lib文件夹,将需要的第三方包拷贝进来.2.将引用的第三方 ...

  8. zookeeper curator ( 实战一)

    目录 zookeeper 的伪集群搭建 写在前面 1.1. zookeeper 安装&配置 1.1.1. 创建数据目录和日志目录: 1.1.2. 创建myid文件 1.1.3. 创建和修改配置 ...

  9. cron表达式(转)

    原文地址:http://www.cnblogs.com/linjiqin/archive/2013/07/08/3178452.html Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或 ...

  10. CUDA:零拷贝主机内存

    The easy way to achieve copy/compute overlap!1.Enable Host Mapping* Runtime: cudaSetDeviceFlags() wi ...