题目链接
想要求长度为M的子序列,我们可以拿DP方程来计算,并且这个DP也是比较好看出来的DP[i][j]代表着i后j位置中的所有长度为j的子序列,递推方程为
for(int i=1;i<=n;i++){
for(int j=2;j<=m;j++){
for(int k=1;k<i;k++){
if(a[k]<a[i]) dp[i][j]+=dp[k][j-1]
}
}
}
}
的一个三重循环,但是n^3的暴力一定是会超时的,所以我们可以用树状数组来优化一个前缀和的过程,每次累加过后记得单点修改以免多次被计算。
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
const int maxn= 1010,mod=1e9+7;
int n,m;
int a[maxn],nums[maxn],cnt,tr[maxn];
int dp[maxn][maxn];
inline void add(int x,int v){
while(x<=cnt){
tr[x]=(tr[x]+v)%mod;
x+=lowbit(x);
}
}
inline int query(int x){
int ans=0;
while(x>0){
ans=(ans+tr[x])%mod;
x-=lowbit(x);
}
return ans;
}
int main(){
int t;
scanf("%d",&t);
int cas=0;
while(t--){
scanf("%d%d",&n,&m);
cnt=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
nums[cnt++]=a[i];
}
sort(nums,nums+cnt);
cnt=unique(nums,nums+cnt)-nums;
for(int i=1;i<=n;i++)
a[i]=lower_bound(nums,nums+cnt,a[i])-nums+1;
for(int i=1;i<=n;i++) dp[i][1]=1;
for(int j=2;j<=m;j++){
for(int i=1;i<=cnt;i++) tr[i]=0;
for(int i=1;i<=n;i++){
dp[i][j]=query(a[i]-1);
add(a[i],dp[i][j-1]);
}
}
int res=0;
for(int i=1;i<=n;i++)
res=(res+dp[i][m])%mod;
printf("Case #%d: %d\n",++cas,res);
}
return 0;
}