题意:n个数,找有多少个长度为m的严格递增子序列
思路:dp[i][j]表示到第i个数,长度为j的这样的序列有几个。dp[i][j] = sum{ dp[k][j-1] },(k < i 且 a[k] < a[i]),n^3的时间复杂度。我们用树状数组来计算这个sum。树状数组的话,我们第一层循环遍历的数,必须是递增的。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<stdlib.h>
#include<math.h>
#include<vector>
#include<list>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<algorithm>
#include<numeric>
#include<functional>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn = 2005;
const int MOD = 1e9+7;
int a[maxn],p[maxn];
int n,tree[maxn][maxn],dp[maxn][maxn];
void init()
{
memset(tree,0,sizeof tree);
}
int cmp(const int &x,const int &y)
{
if(a[x] < a[y]) return 1;
else if(a[x] == a[y])
{
if(x > y) return 1;
else return 0;
}
else return 0;
}
int lowbit(int k)
{
return k & -k;
}
void add(int cnt,int c,int val)
{
while(cnt <= n) // n -> num of point
{
tree[cnt][c] += val;
tree[cnt][c] %= MOD;
cnt += lowbit(cnt);
}
}
int fid(int cnt,int c) // 1 ~ k sum
{
int sum = 0;
while(cnt)
{
sum += tree[cnt][c];
sum %= MOD;
cnt -= lowbit(cnt);
}
return sum;
}
int main(void)
{
int T,kase = 1,m;
scanf("%d",&T);
while(T--)
{
init();
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
p[i] = i;
}
sort(p+1,p+1+n,cmp);
for(int i = 1; i <= n; i++)
{
int index = p[i];
dp[index][1] = 1;
add(index,1,1);
for(int j = 2; j <= m; j++)
{
dp[index][j] = fid(index-1,j-1);
add(index,j,dp[index][j]);
}
}
ll ans = 0;
for(int i = 1; i <= n; i++)
ans = (ans + dp[i][m]) % MOD;
printf("Case #%d: %lld\n",kase++,ans);
}
return 0;
}