题目链接:严格上升子序列数
分析
普通的DP:设
d
i
,
j
d_{i,j}
di,j为以第
i
i
i个数结尾,长度为
j
j
j的严格上升子序列个数。
转移显然。
时间复杂度
O
(
T
n
2
m
)
O(Tn^2m)
O(Tn2m)不能通过。
优化:将数组离散化,建立m个树状数组维护长度为1~m的方案数。复杂度 O ( T n m ∗ l o g n ) O(Tnm*logn) O(Tnm∗logn)
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
struct lwx
{
ll s,p;
}a[100001];
const int mod=1000000007;
ll t,n,m,ans;
ll c[1001][1001],f[1001][1001];
int cmp(lwx l,lwx r)
{
if(l.s==r.s) return l.p>r.p;
else return l.s<r.s;
}
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int y,int z)
{
for(int i=x;i<=n;i+=lowbit(i)) c[i][y]=(c[i][y]+z)%mod;
}
ll getsum(int x,int y)
{
ll sum=0;
for(int i=x;i>0;i-=lowbit(i)) sum=(sum+c[i][y])%mod;
return sum;
}
int main()
{
cin>>t;
for(int k=1;k<=t;k++)
{
memset(c,0,sizeof(c));
memset(f,0,sizeof(f));
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].s);
a[i].p=i;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(j==1) f[i][j]=1;
else f[i][j]=getsum(a[i].p-1,j-1);
update(a[i].p,j,f[i][j]);
}
}
ans=0;
for(int i=m;i<=n;i++)//至少m个,m开始
{
ans=(ans+f[i][m])%mod;
}
printf("Case #%lld: %lld\n",k,ans);
}
return 0;
}