• bzoj3591: 最长上升子序列


    靖爷的仙仙题,其实并不难,可是想了挺久,码了挺久,调了挺久,本人菜鸡了挺久,还是不够专注

    就是问n的排列中,最长上升子序列长度为k的方案数,同时有一些约束

    不难想到把求lis的单调栈压下来,但是还要压一个这个数字用了没有,状态数就是2^2n的了。感觉这个做法不对然后就想歪了

    其实可以把这个东西压成三进制的,0不存在,1存在且在单调栈,2存在且已出单调栈,注意1,2不能调换,不然枚举顺序就出问题了

    详情见代码。卡常没卡过

     

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int _=1e2;
    const int maxn=15+2;
    const int fbin=(1<<15)+_;
    const int tbin=14348907+_;
    int n,li;
    
    int m,num[maxn],rk[maxn],sf[fbin];
    void getsf()
    {
        for(int i=1;i<=m;i++)rk[num[i]]=i;
        for(int zt=0;zt<li;zt++)
        {
            sf[zt]=m+1;
            for(int i=1;i<=m;i++)
                if(!(zt&(1<<num[i]-1))){sf[zt]=i;break;}
        }
    }
    
    int dl[maxn][fbin],o[fbin];//单调栈加入i时,踢那个点 
    void getdl()
    {
        for(int zt=0;zt<li;zt++)
        {
            int p=0;
            for(int i=n;i>=1;i--)
                if(zt&(1<<i-1))p=i;
                else dl[i][zt]=p;
            o[zt]=o[zt>>1]+(zt&1);
        }
    }
    
    int mi[maxn],f[tbin];//0不存在,1存在且在单调栈,2存在且已出单调栈
    void divi(int zt,int &xx,int &yy)//该三进制是由(这个数是否存在)(这个数是否在单调栈里)两个二进制压缩而成的
    {
        xx=0,yy=0;
        for(int i=1;i<=n;i++)
        {
            int d=zt/mi[i-1]%3;
            if(d>=1)xx|=(1<<i-1);
            if(d==1)yy|=(1<<i-1);
        }
    }
    int main()
    {
        freopen("a.in","r",stdin);
        freopen("a.out","w",stdout);
        scanf("%d%d",&n,&m);li=(1<<n);
        mi[0]=1;for(int i=1;i<=n;i++)mi[i]=mi[i-1]*3;
        if(m==1){puts("1");return 0;}
        
        for(int i=1;i<=m;i++)scanf("%d",&num[i]);
        getsf();
        getdl();
        
        int ans=0;f[0]=1;
        for(int zt=0;zt<mi[n];zt++)
            if(f[zt])
            {
                int xt,yt;
                divi(zt,xt,yt);    if(xt==li-1&&o[yt]==m)ans+=f[zt];
                for(int i=1;i<=n;i++)
                    if(!(xt&(1<<i-1)) && rk[i]<=sf[xt])
                        f[zt+mi[dl[i][yt]-1]+mi[i-1]]+=f[zt];
            }
        printf("%d
    ",ans);
        
        
        return 0;
    }

     

     

  • 相关阅读:
    『空』
    退役前的做题记录 Ⅰ
    BZOJ3600 没有人的算术(替罪羊树,线段树)
    洛谷P5324 [BJOI2019]删数(线段树)
    洛谷P4696 [CEOI2011]Matching(KMP)
    Leetcode 638 大礼包 DP
    Leetcode 86 分割链表
    Leetcode 71 简化路径
    Leetcode 17.15 最长单词 剪枝与记忆化
    Leetcode 17.22单词转换 dfs+回溯+剪枝
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/10852857.html
Copyright © 2020-2023  润新知