nssl1187-排列【dp,随机卡常,树状数组】

版权声明:原创,未经作者允许禁止转载 https://blog.csdn.net/Mr_wuyongcong/article/details/82958663

正题


题目大意

一个由 1 n 1\sim n 组成的序列
求长度为k的上升序列的个数。
数据保证随机


解题思路

f i , j f_{i,j} 表示长度为i,以j结尾的上升序列个数。
然后
f i , j = f i 1 , k ( a j > a k , j > k ) f_{i,j}=\sum f_{i-1,k}(a_j>a_k,j>k)
这是 O ( n 3 ) O(n^3)
我们需要优化,所以我们可以用树状数组,下标表示值。
然后每次加 f i 1 , j f_{i-1,j} 进去,然后用查询到 a [ j ] 1 a[j]-1 的前缀和。
这程序就变成了 O ( n 2   l o g 2   n ) O(n^2\ log_2\ n)
但是依旧不能过,这时我们就要用随机的性质。
因为最长不上升子序列的期望长度为 n \sqrt n 个,所以我们可以如果得出该长度的答案为0时,证明这已经是最长的了,所以我们可以以后的都输出0
那么时间复杂度期望为: O ( n n   l o g 2   n ) O(n\sqrt n\ log_2\ n)


code

#pragma GCC optimize(2)
%:pragma GCC optimize(3)
%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
%:pragma GCC optimize("-fgcse")
%:pragma GCC optimize("-fgcse-lm")
%:pragma GCC optimize("-fipa-sra")
%:pragma GCC optimize("-ftree-pre")
%:pragma GCC optimize("-ftree-vrp")
%:pragma GCC optimize("-fpeephole2")
%:pragma GCC optimize("-ffast-math")
%:pragma GCC optimize("-fsched-spec")
%:pragma GCC optimize("unroll-loops")
%:pragma GCC optimize("-falign-jumps")
%:pragma GCC optimize("-falign-loops")
%:pragma GCC optimize("-falign-labels")
%:pragma GCC optimize("-fdevirtualize")
%:pragma GCC optimize("-fcaller-saves")
%:pragma GCC optimize("-fcrossjumping")
%:pragma GCC optimize("-fthread-jumps")
%:pragma GCC optimize("-funroll-loops")
%:pragma GCC optimize("-fwhole-program")
%:pragma GCC optimize("-freorder-blocks")
%:pragma GCC optimize("-fschedule-insns")
%:pragma GCC optimize("inline-functions")
%:pragma GCC optimize("-ftree-tail-merge")
%:pragma GCC optimize("-fschedule-insns2")
%:pragma GCC optimize("-fstrict-aliasing")
%:pragma GCC optimize("-fstrict-overflow")
%:pragma GCC optimize("-falign-functions")
%:pragma GCC optimize("-fcse-skip-blocks")
%:pragma GCC optimize("-fcse-follow-jumps")
%:pragma GCC optimize("-fsched-interblock")
%:pragma GCC optimize("-fpartial-inlining")
%:pragma GCC optimize("no-stack-protector")
%:pragma GCC optimize("-freorder-functions")
%:pragma GCC optimize("-findirect-inlining")
%:pragma GCC optimize("-fhoist-adjacent-loads")
%:pragma GCC optimize("-frerun-cse-after-loop")
%:pragma GCC optimize("inline-small-functions")
%:pragma GCC optimize("-finline-small-functions")
%:pragma GCC optimize("-ftree-switch-conversion")
%:pragma GCC optimize("-foptimize-sibling-calls")
%:pragma GCC optimize("-fexpensive-optimizations")
%:pragma GCC optimize("-funsafe-loop-optimizations")
%:pragma GCC optimize("inline-functions-called-once")
%:pragma GCC optimize("-fdelete-null-pointer-checks")
#include<cstdio>
#include<cstring>
#include<cctype>
#define BPM (int(1e9)+7)
#define lobit(x) x&-x
#define ll long long
using namespace std;
ll t,n,a[10001],f[301][10001],ans,c[10001];
bool flag=true;
int read() {
	int x=0,f=1; char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
	while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
	return x*f;
}//快读
void print(int x){
	if (x>9) print(x/10); putchar(x%10+48); return;
}//快输
void change(ll x,ll a)
{
    while(x<=n)
    {
        (c[x]+=a)%=BPM;
        x+=lobit(x);
    }
}
ll ask(ll x)
{
    ll sum=0;
    while(x)
    {
        (sum+=c[x])%=BPM;
        x-=lobit(x);
    }
    return sum;
}
int main()
{
    scanf("%lld",&t);
    for(ll ti=1;ti<=t;ti++)
    {
        flag=true;
        memset(f,0,sizeof(f));
        n=read();
        for(ll i=1;i<=n;i++)
            a[i]=read();
        for(ll i=1;i<=n;i++)
          f[1][i]=1;
        print(n);putchar(' ');
        for(ll l=2;l<=n;l++)
        {
            memset(c,0,sizeof(c));
            ans=0;
            if(flag)//是否有更长的
              for(ll i=1;i<=n;i++)
              {
                f[l][i]=ask(a[i]-1);
                change(a[i],f[l-1][i]);
                (ans+=f[l][i])%=BPM;
              }//动态转移
            print(ans);
            if(!ans) flag=0;//没有更长的
            if(l!=n) putchar(' ');
        }
        putchar('\n');
    }
}

猜你喜欢

转载自blog.csdn.net/Mr_wuyongcong/article/details/82958663