3 2 1 1 2 7 3 1 7 3 5 9 4 8
2 12给出n个数的序列,给定m,求这n个数中有多少个长度为m的严格上升子序列.
(1<=n<=10000 1<=m<=100 序列中的数字x满足0<=x<=987654321,结果对123456789取余)
比如 序列 1 1 2 n=3,m=2 那么满足的序列有 1 2 和 1 2 一共有两个。
统计问题向树状数组那方面想,如果把输入的x看作一个位置的话,那最多需要开辟987654321个位置,假如是这样的话那我们就可以利用桶排序的思想来做这个题,而实际上我们开不出来这样的大数组. 考虑统计的时候按该数的数值大小在所有数中排第几(用数组rank表示,从小到大)来进行开辟位置,那么最多开辟10000个位置。也就是将具体的数和该数在所有数中的rank进行映射。
比如数 1 4 4 2 8 那么 1的rank为1,2的rank为2,4的rank为3,8的rank为4,这样每个数都有对应rank的映射 1 3 3 2 4。
令dp[i][j] 表示以第i个数结尾且长度为j的上升子序列,1<=i<=n, 1<=j<=m。
那么有递推公式 dp[i][j]= ∑ dp[k][j-1] ( 1<=k<=i-1&& num[k]<num[i]) num[i]为输入的数
一开始dp[i][1]=1;1<=i<=n,其它的全部初始化为0.
以1 4 4 2 m=2为例说明一下树状数组的统计过程:首先准备工作, 数和rank映射 mp[1]=1 mp[2]=2 mp[4]=3 。对应到输入序列的每个位置上则是 p[1]=1 p[2]=3 p[3]=3 p[4]=2 。dp[1][1]=1 dp[2][1]=1 dp[3][1]=1 dp[4][1]=1。
dp[i][j] 当j=2时,遍历n,dp[1][2],首先第一个数1在树状数组中的位置排第一,此时它前面没有数,即dp[1][2]=0
然后第二个数4在树状数组中的位置排第3,此时它前面有1个1,且那个1表示长度为1且1<4,所以dp[2][2]=1
然后dp[3][2]=1
然后dp[4][2]=1
所以一共的符合条件的序列个数为 ∑dp[i][m]
#include <iostream> #include <stdio.h> #include <algorithm> #include <string.h> #include <map> using namespace std; #define mod 123456789 int dp[10001][101];//dp[i][j]代表以第i个数结尾的长度为j的上升子序列的个数 int num[10001];//输入的原始数据 int N;//消除重复元素后还剩多少个数 map<int,int> mp;//这个地方不能将mp开成数组形式,因为我们开不了那么大. int pos[10001];//第i个位置的数在所有数中排第几个 int c[10001];//树状数组部分 int lowbit(int x) { return x&(-x); } int sum(int p) { int ans=0; while(p>0) { ans=(ans%mod+c[p]%mod)%mod; p=p-lowbit(p); } return ans; } void add(int p,int val) { while(p<=N) { c[p]=(c[p]+val)%mod; p=p+lowbit(p); } } int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF) { memset(dp,0,sizeof(dp)); int temp[10001];//num的备份数据用来去重操作 for(int i=1;i<=n;i++) { scanf("%d",&num[i]); temp[i]=num[i]; dp[i][1]=1; } sort(temp+1,temp+1+n); N=unique(temp+1,temp+1+n)-(temp+1); for(int i=1;i<=N;i++) mp[temp[i]]=i;//具体的数在所有数中排第几 for(int i=1;i<=n;i++) pos[i]=mp[num[i]];//输入位置和排第几映射 for(int j=2;j<=m;j++) { memset(c,0,sizeof(c)); for(int i=1;i<=n;i++) { dp[i][j]=sum(pos[i]-1);//求小于num[i]且长度为j-1的和 add(pos[i],dp[i][j-1]); //把c数组的pos[i]位置更新成dp[i][j-1] } } int ans=0; for(int i=1;i<=n;i++) ans=(ans%mod+dp[i][m]%mod)%mod; cout<<ans<<endl; } return 0; }