• 小清新签到题(DP)


    传送门

    然鹅我并不觉得这道题很清新rua

    思维巧妙!(参考

    对于第k小,我们可以这样考虑,若是第k小,那么比它小的方案应该是有k-1个。

    在排列组合中,若固定i放在j位置,方案数是确定的,即:i固定在j位置,满足这个条件的序列的rank是在一个范围内的。

    对于逆序对

    常见思考方式是从小到大枚举数字,考虑对逆序对个数做出的贡献(从小到大插入,后插入不会对前插入造成影响)

    设f[i][j]为i个数,j个逆序对的方案数,可得转移方程为

    f[i][j]=f[i-1][j]+f[i-1][j-1]+……+f[i-1][j-i+1]

    (就相当于给一个比序列中所有数都大的数,让你往里插。)

    可用前缀和优化(注意是一层一层的前缀和而不是二维前缀和)

    然后我们可以一个个从后往前放数,枚举每一位可以放什么数(1~n),统计放这个数所造成的贡献num,以及之前可以放的数(但因为达不到k而被放弃)的方案数tmp。(但tmp在算这一次放的数是否达到逆序对要求时要加上)

    注意f数组容易爆LL,但k的范围是1e13,所以超过了就改为k+1即可。

    #include<bits/stdc++.h>
    #define LL long long 
    #define N 303
    using namespace std;
    LL read()
    {
        LL x=0,f=1;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    LL f[N][N*N],s[N][N*N];//f[i][j]i个数j个逆序对的方案数,s前缀和 
    int ans[N],vis[N];
    void init(LL n,LL k,LL x)
    {
        f[0][0]=1;
        for(int i=0;i<=x;++i)s[0][i]=1;//注意逆序对数可以取到0 
        for(int i=1;i<=n;++i)
        {
            for(int j=0;j<=x;++j)
            {
                int l=max(0,j-i+1),r=j;
                LL tmp=(l==0)?s[i-1][r]:(s[i-1][r]-s[i-1][l-1]);
                f[i][j]=min(tmp,k+1);
                s[i][j]=f[i][j]+s[i][j-1];
            }
        }
    }
    int main()
    {
        LL n=read(),k=read(),x=read();
        init(n,k,x);
    //    for(int i=1;i<=n;++i)
    //      for(int j=1;j<=x;++j)
    //        printf("%lld
    ",f[i][j]);
        for(int i=n;i>=1;--i)
        {
            LL tmp=0;
            for(int j=1;j<=n;++j)
            {
                if(vis[j])continue;
                int num=j-1;//对逆序对个数最多产生的贡献,也就是比它小的都在它后面这种情况
                for(int l=1;l<j;++l)num-=vis[l];
                if(tmp+f[i-1][x-num]>=k)
                {
                    ans[n-i+1]=j;//可以确定这个位置填j 
                    vis[j]=1;x-=num;k-=tmp;
                    break;
                } 
                tmp+=f[i-1][x-num];//!!! 
            }
        }
        for(int i=1;i<=n;++i)
          printf("%d ",ans[i]);
    } 
    View Code
  • 相关阅读:
    Spring3.0 AOP 具体解释
    bcompare3+keygen
    解决git每次输入密码,设置gitlab、github默认push的用户名和密码
    15款免费WiFi入侵破解安全测试工具
    六款主流免费网络嗅探软件wireshark,tcpdump,dsniff,Ettercap,NetStumbler
    wan口mac=lan口mac加一,wlan是lan口mac加二
    MOUNT MACBOOK DISK (OSX / HFS+) ON UBUNTU 12.04 LTS WITH READ/WRITE
    /sbin/ifup: configuration for eth0 not found解决
    delete
    vbox安装mac os x
  • 原文地址:https://www.cnblogs.com/yyys-/p/11360156.html
Copyright © 2020-2023  润新知