zoukankan      html  css  js  c++  java
  • 【BZOJ4416】阶乘字符串(SHOI2013)-状压DP

    测试地址:阶乘字符串
    做法:本题需要用到状压DP。
    首先,根据证明(直觉),满足条件的字符串的最小长度仅仅比n2小一点点,因此当n>21时,直接输出NO即可。
    于是我们就把n缩减到了21的范围,就可以考虑状压了。令f(i)为包含集合i的所有全排列的最短前缀,而nxt(i,j)为第i个字符后第一个字符j的位置,那么有:
    f(i)=max{nxt(f(i{x}),x)|xi}
    上式的含义是,枚举集合i内的一个字符x,求包含以字符x结尾,前面为其余字符的全排列的最短前缀,那么这些条件都要满足的话,答案显然就是它们的最大值。于是我们求出f(S)S为字符集)后,判断一下它是不是不超过字符串长度即可,时间复杂度为O(n2n)
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    int T,n,len,nxt[460][22],f[2200000];
    char s[460];
    
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
            scanf("%s",s);
            len=strlen(s);
    
            if (n>21)
            {
                printf("NO
    ");
                continue;
            }
    
            for(int i=0;i<n;i++)
                nxt[len][i]=len;
            for(int i=len-1;i>=0;i--)
            {
                for(int j=0;j<n;j++)
                    nxt[i][j]=nxt[i+1][j];
                nxt[i][s[i]-'a']=i;
            }
    
            int now=0;
            for(int i=1;i<(1<<n);i++)
            {
                if (i==(1<<now))
                {
                    f[i]=nxt[0][now];
                    now++;
                    continue;
                }
                f[i]=0;
                for(int j=0;j<n;j++)
                    if (i&(1<<j))
                        f[i]=max(f[i],nxt[f[i^(1<<j)]][j]);
            }
            if (f[(1<<n)-1]<len) printf("YES
    ");
            else printf("NO
    ");
        }
    
        return 0;
    }
  • 相关阅读:
    让Python支持中文注释
    【转】python入门指引
    【转】布同:如何循序渐进学习Python语言
    在nagios中监控windows主机系统地址的状态
    大神
    music
    20·15-01-21
    2015-01-20
    2015-01-19
    2015-01-18
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793313.html
Copyright © 2011-2022 走看看