zoukankan      html  css  js  c++  java
  • BZOJ4416 SHOI2013阶乘字符串(状压dp)

      当n大到一定程度(>21)时一定无解,并不会证。

      如果要取出一个排列,显然应该让每一位在序列中的位置尽量靠前。于是设f[S]表示存在S子集中这些字母所组成的所有排列的最短前缀的长度,枚举当前排列最后一个字母转移即可。

    #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 510
    #define M 21
    int T,n,m,a[N],f[1<<M],nxt[N][M];
    char s[N];
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj4416.in","r",stdin);
        freopen("bzoj4416.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        T=read();
        while (T--)
        {
            m=read();scanf("%s",s+1);n=strlen(s+1);
            if (m>21) {cout<<"NO"<<endl;continue;}
            for (int i=1;i<=n;i++) a[i]=s[i]-'a';
            for (int i=0;i<m;i++) nxt[n][i]=nxt[n+1][i]=n+1;
            for (int i=n-1;i>=0;i--)
                for (int j=0;j<m;j++)
                nxt[i][j]=a[i+1]==j?i+1:nxt[i+1][j];
            memset(f,0,sizeof(f));
            int S=(1<<m)-1;
            for (int i=1;i<=S;i++)
                for (int j=0;j<m;j++) 
                if (i&(1<<j)) f[i]=max(f[i],nxt[f[i^(1<<j)]][j]);
            if (f[S]<=n) cout<<"YES"<<endl;
            else cout<<"NO"<<endl;
        }
        return 0;
    }
  • 相关阅读:
    正则表达式语法参考
    Informix触发器实例
    .net core 时间与时间戳的转换
    获取对象字段的值
    .NET 6 运行在Win7 SP1上出错解决方法
    写在2012,腊月二十八
    2011年度工作&生活总结
    终于在博客园上开通自己的blog了
    观察进程的内存占用情况
    从一个登录页面浅淡MVVM(二)
  • 原文地址:https://www.cnblogs.com/Gloid/p/9871112.html
Copyright © 2011-2022 走看看