http://acm.split.hdu.edu.cn/showproblem.php?pid=5542
长度为n的序列,求该序列中有多少个长度为m的单调递增子序列。
dp[i][j] 以a[i]结尾,长度为j的,严格上升子序列的数量
dp[i][j]=sum{dp[k][j-1]},k<=i且a[k]
#include <iostream>
#include <algorithm>
#include <string.h>
#include <stdio.h>
#define MOD 1000000007
using namespace std;
int a[1010];
int dp[1010][1010]; // 到第 i 个数字,长度为 j 的单调递减子序列的个数
int b[1010];
int n,m;
int lowbit(int x){
return (x) & -(x);
}
int sum(int x,int y) //在前x项中,有多少种长度为y的子序列
{
int res = 0;
while(x){
res = (res + dp[x][y]) % MOD;
x -= lowbit(x);
}
return res;
}
void add(int x,int y,int d) //更新x及以上长度,能取到的y的值为d
{
while(x <= n){
dp[x][y] = (dp[x][y] + d) % MOD;
x += lowbit(x);
}
}
int main(){
int T;
scanf("%d",&T);
for( int t = 1; t <= T; t++){
memset(dp,0,sizeof(dp));
scanf("%d%d",&n,&m);
for (int i = 1; i <= n; i++){
scanf("%d",&a[i]);
b[i] = a[i];
}
sort(a+1,a+1+n);
for (int i = 1; i <= n; i++){
int pos=lower_bound(a+1,a+1+n,b[i])-a;
for (int j = 1; j <= min(i+1,m); j++){
if (j == 1)
add(pos,1,1);
else{
int temp = sum(pos-1,j - 1);
add(pos,j,temp);
}
}
}
printf("Case #%d: %d\n",t,sum(n,m));
}
return 0;
}