求最长上升子序列方案数。

转载自:http://blog.csdn.net/u013445530/article/details/47958617,如造成不便,请博主联系我。

数组A包含N个整数(可能包含相同的值)。设S为A的子序列且S中的元素是递增的,则S为A的递增子序列。如果S的长度是所有递增子序列中最长的,则称S为A的最长递增子序列(LIS)。A的LIS可能有很多个。例如A为:{1 3 2 0 4},1 3 4,1 2 4均为A的LIS。给出数组A,求A的LIS有多少个。由于数量很大,输出Mod 1000000007的结果即可。相同的数字在不同的位置,算作不同的,例如 {1 1 2} 答案为2。 
Input 
第1行:1个数N,表示数组的长度。(1 <= N <= 50000) 
第2 - N + 1行:每行1个数A[i],表示数组的元素(0 <= A[i] <= 10^9) 
Output 
输出最长递增子序列的数量Mod 1000000007。 
Input示例 






Output示例 
2

必须用nlogn算法,否则超时,那么我们如何计算LIS的个数呢?

先开始我想到的是o(n^2)的做法,很容易理解

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const int M = 500000+100; int a[M];
int c[M];
int dp[M];
long long cent[M]; int INF = 1e9 + 1000;
const int mod =1000000007; int input()
{
int ans=0;
char a;
while((a=getchar())<'0'||a>'9');
ans=a-'0';
while((a=getchar())>='0'&&a<='9')
{
ans=ans*10+a-'0';
}
return ans;
} int main()
{
int n;
#ifdef xxz
freopen("in.txt","r",stdin);
#endif // xxz while(~scanf("%d",&n))
{
for(int i = 0; i < n; i++) a[i] = input() , cent[i] = 1;
int Max = 0; fill(dp,dp+n,0);
long long ans = 0;
for(int i = 0; i < n; i++)
{
dp[i] = 1;
for(int j = 0; j < i; j++)
{
if(a[j] < a[i])
{
if(dp[i] < dp[j] + 1)
{
dp[i] = dp[j] + 1;
cent[i] = cent[j];
}
else if(dp[i] == dp[j] + 1) cent[i] = (cent[i] +cent[j])%mod;
}
} Max = max(Max,dp[i]); } for(int i = 0; i < n; i++)
{
if(dp[i] == Max) ans = (ans + cent[i]) % mod;
} printf("%d\n",ans%mod);
} return 0;
}

然后从网上搜nlogn的算法没搜到,然后问了好多大神,九爷,鸟神,rabbit,都说用线段树或者树状数组搞,好吧,没搞出来。

然后问tyh,他搜到了一篇国外高手写的思路,看完以后直接转换为代码 
二分+前缀和,orz….膜拜田博士…….. 
果然搜索姿势要正确呀 
思路地址: 
http://stackoverflow.com/questions/22923646/number-of-all-longest-increasing-subsequences

我用中文解释下: 
就是取二元组(i,j),i表示以i元素结尾的序列,j表示方案数 
比如: 
add 1 
len1: (1,1);

add 2:

len1(1,1); 
len2(2,1);

add 5 
len1 (1,1); 
len2 (2,1); 
len3 (5,1);

add 4 
len1 (1,1); 
len2 (2,1); 
len3 (5,1) (4,1); 
……

我们可以找到规律,就是没一行j都是从达到小减少 
新插入一个数,我们先找它应该处于哪一行,用 
就是用LIS的nlogn算法找,它的方案数就等于它上一行比这个数小的所有方案和


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
using namespace std; typedef long long LL;
const int MOD = 1e9 + 7;
const int INF = 0x7fffffff;
const int N = 50000 + 10; vector <int> val[N]; // val[i]: 最大长度为i+1的序列的最后一个元素组成的序列
vector <int> sum[N]; // sum[i]: 对应val中每个序列数量的组成的前缀和。
vector <int> last(N, INF); // last[i]: val[i].back() int input()
{
int ans=0;
char a;
while((a=getchar())<'0'||a>'9');
ans=a-'0';
while((a=getchar())>='0'&&a<='9')
{
ans=ans*10+a-'0';
}
return ans;
} void add(int x, int len, int v)
{
val[len].push_back(x);
if(sum[len].size() == 0)
{
sum[len].push_back(v);
}
else
{
sum[len].push_back((sum[len].back() + v) % MOD);
}
last[len] = x;
} int main()
{ int n, x;
while (scanf("%d", &n) != EOF)
{
int Max = 0;
for(int i = 0; i < n; i++)
{
x = input();
int len = lower_bound(last.begin(), last.end(), x) - last.begin();
Max = max(Max, len);
if(len == 0)
{
add(x, len, 1);
}
else
{
int pos = upper_bound(val[len - 1].begin(), val[len - 1].end(), x,greater<int>() ) - val[len - 1].begin();
int cnt;
if(pos == 0)
{
cnt = sum[len - 1].back();
}
else
{
cnt = (sum[len - 1].back() - sum[len - 1][pos - 1] + MOD) % MOD;
}
add(x, len, cnt);
}
}
printf("%d\n", sum[Max].back());
} return 0;
}

【二分】【动态规划】Gym - 101156E - Longest Increasing Subsequences的更多相关文章

  1. 【Codeforces】Gym 101156E Longest Increasing Subsequences LIS+树状数组

    题意 给定$n$个数,求最长上升子序列的方案数 根据数据范围要求是$O(n\log n)$ 朴素的dp方程式$f_i=max(f_j+1),a_i>a_j$,所以记方案数为$v_i$,则$v_i ...

  2. SnackDown Longest Increasing Subsequences 构造题

    Longest Increasing Subsequences 题目连接: https://www.codechef.com/SNCKPA16/problems/MAKELIS Description ...

  3. Longest Increasing Subsequences(最长递增子序列)的两种DP实现

    一.本文内容 最长递增子序列的两种动态规划算法实现,O(n^2)及O(nlogn).     二.问题描述 最长递增子序列:给定一个序列,从该序列找出最长的 升序/递增 子序列. 特点:1.子序列不要 ...

  4. 300. Longest Increasing Subsequence(LIS最长递增子序列 动态规划)

    Given an unsorted array of integers, find the length of longest increasing subsequence. For example, ...

  5. [LeetCode] Longest Increasing Subsequence 最长递增子序列

    Given an unsorted array of integers, find the length of longest increasing subsequence. For example, ...

  6. [LeetCode] Number of Longest Increasing Subsequence 最长递增序列的个数

    Given an unsorted array of integers, find the number of longest increasing subsequence. Example 1: I ...

  7. 【LeetCode】673. Number of Longest Increasing Subsequence

    题目: Given an unsorted array of integers, find the number of longest increasing subsequence. Example ...

  8. [LeetCode] 300. Longest Increasing Subsequence 最长递增子序列

    Given an unsorted array of integers, find the length of longest increasing subsequence. Example: Inp ...

  9. [LeetCode] 673. Number of Longest Increasing Subsequence 最长递增序列的个数

    Given an unsorted array of integers, find the number of longest increasing subsequence. Example 1: I ...

随机推荐

  1. mybatis查询参数为0时无法识别问题

    最近在工作中遇到一个mybatis参数问题,主要是列表查询按照状态进行过滤,其中已完成状态值是0,被退回是1.如图所示 , 然后Mapper里面是和平常一样的写法<if test="s ...

  2. 利用Volatility对Linux内存取证分析-常用命令翻译

    命令翻译 linux_apihooks - 检查用户名apihooks linux_arp - 打印ARP表 linux_aslr_shift - 自动检测Linux aslr改变 linux_ban ...

  3. RabbitMQ--work queues(二)

    封装一个task到一个message,并发送到queue.consumer会去除task并执行这个task. 这里我们简化了操作,发送消息到队列中,consumer取出消息计算里面'.'号有几个就sl ...

  4. Python基础:内置函数

    本文基于Python 3.6.5的标准库文档编写,罗列了英文文档中介绍的所有内建函数,并对其用法进行了简要介绍. 下图来自Python官网:展示了所有的内置函数,共计68个(14*4+12),大家可以 ...

  5. 数据库-mysql中文显示问题

    一:在mysql 下面查看带中文的记录显示乱码 mysql> select * from role; +----+------+ | id | name | +----+------+ | 1 ...

  6. python网络编程--线程递归锁RLock

    一:死锁 所谓死锁:是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进 ...

  7. R语言以及RStdio的安装

    R语言: 首先从官网上下载R安装包, 提供了Linux, (Mac) OS X, Windows的安装包相关下载链接. RStdio: RStdio(官网)是R言语非常实用的IDE, 是一个免费的软件 ...

  8. 【Android开发日记】之入门篇(八)——Android数据存储(下)

    废话不多说了,紧接着来讲数据库的操作吧.Come On! 提到数据存储问题,数据库是不得不提的.数据库是用来存储关系型数据的不二利器.Android为开发者提供了强大的数据库支持,可以用来轻松地构造基 ...

  9. mac下---charles抓包https

    网上找的很多安装包都有问题,终于找到个可用的! 下载地址:  http://pan.baidu.com/s/1pLAONbX ———————————————————————————— 教程转载:htt ...

  10. 链家2018春招C/C++开发实习生在线考试编程题

    题目一 题解:该题目意思就是让你输入n组数据,然后求并集,利用STL容器set集合的特性:元素不重复存储,我们可以很轻易得出答案 #include <iostream> #include ...