题目:度度熊了解到,1,2,…,n 的排列一共有 n!=n×(n−1)×⋯×1 个。现在度度熊从所有排列中等概率随机选出一个排列 p1,p2,…,pn,你需要对 k=1,2,3,…,n 分别求出长度为 k 的上升子序列个数,也就是计算满足 1≤a1 < a2 < … < ak ≤n 且 pa1 <pa2< … < pak 的 k 元组 (a1,a2,…,ak) 的个数。 由于结果可能很大,同时也是为了 ruin the legend, 你只需要输出结果对 1000000007(=109+7) 取模后的值。
思路:因为是随机排列,循环长度用树状数组维护长度为len-1时的答案,滚动数组更新dp就行了。n*nlogn,随机序列能过的。。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e4+10;
const ll mod=1e9+7;
int t,n,a[maxn];
ll dp[2][maxn],c[maxn],ans[maxn];
int lowbit(int x){return x&-x;}
void update(int pos,int val)
{
while(pos<=n)
{
(c[pos]+=val)%=mod;
pos+=lowbit(pos);
}
}
ll query(int pos)
{
ll ans=0;
while(pos>0)
{
(ans+=c[pos])%=mod;
pos-=lowbit(pos);
}
return ans;
}
int main()
{
scanf("%d",&t);
int cas=0;
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
dp[1][i]=1;
}
memset(ans,0,sizeof ans);
ans[1]=n;
for(int len=2;len<=n;len++)
{
if(ans[len-1]==0) break;
for(int i=1;i<=n;i++)
{
ll tmp=query(a[i]-1);
(ans[len]+=tmp)%=mod;
dp[len&1][i]=tmp;
update(a[i],dp[(len-1)&1][i]);
}
memset(c,0,sizeof c);
}
printf("Case #%d:",++cas);
for(int i=1;i<=n;i++)
printf(" %lld",ans[i]);
puts("");
}
return 0;
}