算法分析:
首先很容易想到 dp (没做过最长上升子序列模板的可以去看看)。
设 表示以 i 结尾,长度为 j 的严格上升子序列的个数。
则:
但一看时间复杂度 肯定超时了。
算法优化:
这时想到了可以用树状数组来维护方案数。
我们将数组离散化,再建m个树状数组,分别维护长度从1到m的方案数,用来优化 dp,复杂度 显然就能过了。
具体实现看代码:
#include<bits/stdc++.h>
#define int long long //一定注意开long long
using namespace std;
inline int read(){ //快读没什么好说的
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48) ; ch=getchar();}
return x*f;
}
const int M = 1010;
const int mod = 1e9+7; //别忘了取模
int n,m;
int sum[M][M],f[M][M]; //sum是维护树状数组 f是用来dp
int T,cnt,ans;
struct dat{
int val,num;
friend bool operator < (dat a,dat b){ //重载运算符,当然在外面写函数也行
if(a.val == b.val) return a.num > b.num;
else return a.val < b.val; //按值从小到大排序
}
}a[M];
inline int lowbit(int x) {return x & (-x);} //树状数组经典操作
void update(int x,int y,int w){ //把x这个位置加上w ,y表示这是第几个树状数组
while(x <= n){
sum[x][y] = (sum[x][y] + w)%mod;
x += lowbit(x);
}
}
int query(int x,int y){ //求x这个位置的值 , y表示这是第几个树状数组
int ans=0;
while(x){
ans = (ans + sum[x][y])%mod; //一定随时取模
x -= lowbit(x);
}
return ans%mod;
}
signed main(){
T=read();
while(T--){
cnt++;
ans = 0;
memset(sum,0,sizeof(sum)); //别忘初始化
n=read(),m=read();
for(register int i(1) ; i<=n ; i=-~i) a[i].val = read(),a[i].num = i; //离散化操作
sort(a+1,a+n+1); //排序
for(register int i(1) ; i<=n ; i=-~i){
for(register int j(1) ; j<=m ; j=-~j){
if(j == 1) f[i][j] = 1;
else f[i][j] = query(a[i].num-1,j-1); //开始dp
update(a[i].num,j,f[i][j]); //然后将值加到树状数组中
}
}
for(register int i(m) ; i<=n ; i=-~i) ans = (ans+f[i][m])%mod; //最后是从每个点开始的方案数之和
printf("Case #%d: %lld\n",cnt,ans%mod);
}
return 0;
}