版权声明:转载无所谓的。。。 https://blog.csdn.net/xuxiayang/article/details/82959337
大意
现在有一个随机排列,你需要对所有的 ,求出长度为 的上升子序列个数
思路
设 表示长度为 的上升子序列以 结尾的个数,得到方程
然后这样是 ,我们可以用树状数组维护前面 比它小的,有点像求逆序对,这样子时间复杂度为 ,然后我们看到这里有一个随机排列,那么也就说明上升子序列的长度期望是 也就是说,有的时候后面子序列一旦出现长度为0的,那么所有后面的都是0
关于空间,可以用 也可以利用期望的特点,开 的空间即可
代码
#include<cstdio>
#include<cstring>
#define max(a,b) (a)>(b)?(a):(b)
#define min(a,b) (a)<(b)?(a):(b)
#define ymw 1000000007
#define LL long long
using namespace std;LL n,t,a[10001],i,f[301][10001],ans,c[10001];
inline LL read()
{
char c;int d=1,f=0;
while(c=getchar(),c<48||c>57)if(c=='-')d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),c>47&&c<58)f=(f<<3)+(f<<1)+c-48;
return d*f;
}
inline void write(LL x){if(x>9)write(x/10);putchar(x%10+48);return;}
inline LL ask(LL x){LL s=0;for(;x>0;x-=x&-x)s+=c[x];return s%ymw;}//树状数组查询
inline void add(LL x,LL y){for(;x<=n;x+=x&-x)(c[x]+=y)%=ymw;return;}//树状数组修改
signed main()
{
t=read();
while(t--)
{
n=read();write(n);putchar(32);
memset(f,0,sizeof(f));for(register int i=1;i<=n;i++)a[i]=read(),f[1][i]=1;
ans=1;
for(i=2;i<=n&&ans;i++)
{
memset(c,0,sizeof(c));
ans=0;
for(register int j=1;j<=n;j++)
{
f[i][j]=ask(a[j]-1);
add(a[j],f[i-1][j]);
(ans+=f[i][j])%=ymw;//动态转移
}
write(ans);//输出
if(i!=n)putchar(32);
}
for(;i<=n;i++) {putchar(48);if(i!=n)putchar(32);}//后面的都是0啊
putchar(10);
}
}