题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5542
题意:n个数中找m个数,使得从左到右读是上升的子序列。问一共有多少种。
dp(i,j)表示取到第i个位置,长为j并且最后一个数为a(i)的方案总数。
更新就比较容易了,dp(i,j)=∑(k=1->j-1)dp(i-1,k),初始化dp(i,1)=1。
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) x & (-x) const int mod = int(1e9+);
const int maxn = ;
int dp[maxn][maxn];
int a[maxn], h[maxn];
int n, m, hcnt; int sum(int i, int x) {
int ret = ;
while(x) {
ret = (ret + dp[i][x]) % mod;
x -= lowbit(x);
}
return ret;
} void update(int i, int x, int k) {
while(x <= n) {
dp[i][x] = (dp[i][x] + k) % mod;
x += lowbit(x);
}
} int getid(int x) {
return lower_bound(h, h+hcnt, x) - h;
} int main() {
//freopen("in", "r", stdin);
int T, _ = ;
scanf("%d", &T);
while(T--) {
printf("Case #%d: ", _++);
scanf("%d %d", &n, &m);
for(int i = ; i <= n; i++) {
scanf("%d", &a[i]);
h[i-] = a[i];
}
sort(h, h+n); hcnt = unique(h, h+n) - h;
for(int i = ; i <= n; i++) a[i] = getid(a[i]) + ;
memset(dp, , sizeof(dp));
for(int i = ; i <= n; i++) {
for(int j = ; j <= m; j++) {
if(j == ) {
update(j, a[i], );
continue;
}
int tmp = sum(j-, a[i]-);
update(j, a[i], tmp);
}
}
printf("%d\n", sum(m, n));
}
return ;
}