zoukankan      html  css  js  c++  java
  • BZOJ3591 最长上升子序列(状压dp)

      之前听说过一种dp套dp的trick,大致是用另一个dp过程中用到的一些东西作为该dp的状态。这个题比较类似。

      考虑求LIS时用到的单调队列。设f[S]为所选取集合为S的方案数,其中在单调队列内的标2不在的标1。转移时考虑选择一个数是否合法,这只需要保证LIS长度不超过k且所给数的相对顺序不变。

      注意dp顺序,从小到大先枚举选了哪些数再枚举哪些在单调队列里。以及注意卡常。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define N 15
    int n,m,id[N],p[N+1],f[15000000];
    bool flag[1<<N][N];
    int v[1<<N][N],c[1<<N],mx[1<<N],s[1<<N],ans=0;
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj3591.in","r",stdin);
        freopen("bzoj3591.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),m=read();
        for (int i=1;i<=m;i++) id[read()-1]=i;
        p[0]=1;for (int i=1;i<=n;i++) p[i]=p[i-1]*3;
        for (int i=0;i<(1<<n);i++)
            for (int j=0;j<n;j++)
            if (!(i&(1<<j)))
            {
                if (!id[j]) flag[i][j]=1;
                else
                {
                    int tot=0;
                    for (int k=0;k<n;k++)
                    if ((i&(1<<k))) tot+=(id[k]>0);
                    if (tot+1==id[j]) flag[i][j]=1;
                }
                int t=-1,x=0;
                for (int k=0;k<n;k++)
                if (i&(1<<k)) x+=p[k];
                for (int k=n-1;k>j;k--)
                if (i&(1<<k)) t=k;
                if (~t) v[i][j]=x-p[t]+p[j];
                else v[i][j]=x+p[j];
            }
            else c[i]+=p[j],mx[i]=max(mx[i],j),s[i]++;
        f[0]=1;
        for (int x=0;x<(1<<n);x++)
            for (int y=x;y>0||y==0&&x==0;x==0?y--:y=y-1&x)
            if (f[c[x]+c[y]])
            {
                int i=c[x]+c[y],z=c[x];
                for (int j=0;s[y]==m?j<mx[y]:j<n;j++)
                if (flag[x][j]) f[z+p[j]+v[y][j]]+=f[i];
                if (x==(1<<n)-1) ans+=f[i];
            }
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    BZOJ 1003--[ZJOI2006]物流运输(最短路)
    BZOJ 1002--[FJOI2007]轮状病毒(高精度)
    BZOJ 1001--[BeiJing2006]狼抓兔子(最短路&对偶图)
    BZOJ 1719--[Usaco2006 Jan] Roping the Field 麦田巨画(几何&区间dp)
    BZOJ 2821--作诗(分块)
    BZOJ 2724--蒲公英(分块)
    BZOJ 2388--旅行规划(分块&单调栈&二分)
    用python操作Git
    JS常用到的日期函数
    Python3.7使用celery出现from . import async, base SyntaxError: invalid syntax错误
  • 原文地址:https://www.cnblogs.com/Gloid/p/9703407.html
Copyright © 2011-2022 走看看