思路:dp[i][k]表示:以a[i]为右端点时长度为k的上升子序列的个数,转换公式比较容易写出来
dp[i][k]=sum{dp[j][k-1]} (a[j]<a[i],j<i)
可以看出有 i,j,k三重循环,时间复杂度为 O(n^3) 会TLE,因此看能不能减小一重循环
又转换方程看出,dp[i][k]为前i-1个a[j]<a[i]的总和,有a[j]<a[i]才能求和,因此可以考虑用树状数组来求和。
遍历排列a[i],用树状数组记录前 a[i] 的总和,则 dp[i][k]=Query(a[i]-1),而dp[i][k]又可以用dp[i]来代替,对于树状数组C[i]的处理,可用d[a[i]]保存a[i]的上升子序列个数,在计算d[a[i]]时先将其重置树状数组
Code :
#include<iostream>
using namespace std;
typedef long long LL;
const int MOD=1e9+7;
const int MAX_N=10005;
int n,T;
int a[MAX_N],d[MAX_N];
LL C[MAX_N];
int ans[MAX_N];
int Lowbit(int x);
void Update(int id,int x);
LL Query(int id);
int main()
{
ios::sync_with_stdio(false);
cin>>T;
for(int t=1;t<=T;++t)
{
cin>>n;
for(int i=1;i<=n;d[i]=1,ans[i]=0,++i)
cin>>a[i];
ans[1]=n;
for(int k=2;k<=n;++k)
{
for(int i=1;i<=n;++i)
C[i]=0;
LL sum=0;
for(int i=1;i<=n;++i)
{
Update(a[i],d[a[i]]);
d[a[i]]=Query(a[i]-1)%MOD;
sum+=d[a[i]];
}
ans[k]=sum%MOD;
if(!ans[k]) break;
}
cout<<"Case #"<<t<<":";
for(int i=1;i<=n;++i)
cout<<" "<<ans[i];
cout<<endl;
}
return 0;
}
int Lowbit(int x)
{
return x&(-x);
}
void Update(int id,int x)
{
while(id<=n){
C[id]+=x;
id+=Lowbit(id);
}
}
LL Query(int id)
{
LL ans=0;
while(id>0){
ans+=C[id];
id-=Lowbit(id);
}
return ans;
}