zoukankan      html  css  js  c++  java
  • bzoj1559 [JSOI2009]密码

    题目链接:[JSOI2009]密码

    我们先看第一问:输出方案数

    我们把所有给出来的串丢到AC自动机里面去,然后在建出来的(trie)图上跑dp

    由于(nleq 10)我们很自然的就想到了状压

    (dp[i][j][sta])表示原串匹配到了第(i)位,在AC自动机里走到了第(j)个节点,已经出现了(sta)个单词(压缩状态)的方案数

    注意到如果有两个串(s_i)(s_j)满足(s_i)(s_j)的子串,那么我们所构建的串并不一定必须要有(s_i),因为如果有了(s_j)那么一定满足了必须有(s_i)

    那么我们可以确定最终统计答案时的(sta),暴力累加即可

    接下来就是第二问:输出方案

    我么先要考虑一下在什么情况需要做第二问,题目中给的条件是(ansleq 42)

    如果此时我们构建的字符串一定有一位“空闲”,即一定有一位可以放置任意字符,而剩下的则必须构成给定的字符串,那么方案数就是(2*26=52>42)(该字符可以放在开头和末尾)

    因此此时一定不需要输出答案

    所以当要进行第二问的时候,一定是只能用所给定的串进行组合

    并且不可能出现的重复的串,因为重复的串是可以变成空闲节点的,这样就和上面一样了

    预处理出对于任意两个字符串(s_i,s_j)(s_i)的后(k)位和(s_j)的前(k)位相等的所有(k)

    然后暴力dfs排序顺序即可

    #include<iostream>
    #include<string.h>
    #include<string>
    #include<stdio.h>
    #include<algorithm>
    #include<math.h>
    #include<vector>
    #include<queue>
    #include<map>
    using namespace std;
    const int maxd=1000000007,N=100000;
    const double pi=acos(-1.0);
    typedef long long ll;
     
    namespace AC{
        struct node{
            int ch[27];
            int fail,end;
            node() {memset(ch,0,sizeof(ch));fail=0;end=0;}
        }point[100100];
        int cnt;
         
        void init()
        {
            cnt=0;
            point[0].fail=0;
        }
         
        void insert(char *s,int id)
        {
            int len=strlen(s),i,now=0;
            for (i=0;i<len;i++)
            {
                if (!point[now].ch[s[i]-'a'])
                {
                    point[now].ch[s[i]-'a']=(++cnt);
                    point[cnt]=node();
                }
                now=point[now].ch[s[i]-'a'];
            }
            point[now].end=(1<<(id-1));
        }
         
        void get_fail()
        {
            queue<int> q;
            int i;
            for (i=0;i<26;i++)
            {
                if (point[0].ch[i])
                {
                    point[point[0].ch[i]].fail=0;
                    q.push(point[0].ch[i]);
                }
            }
            while (!q.empty())
            {
                int u=q.front();q.pop();
                for (i=0;i<26;i++)
                {
                    if (point[u].ch[i])
                    {
                        point[point[u].ch[i]].fail=point[point[u].fail].ch[i];
                        q.push(point[u].ch[i]);
                    }
                    else point[u].ch[i]=point[point[u].fail].ch[i];
                }
            }
        }
    }
    using namespace AC;
    int n,m,len[20],restm,LINK[50][50],ansord[50];
    ll dp[2][110][1030];
    char s[20][20];
    bool del[20];
     
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
        while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
        return x*f;
    }
     
    int getl(int u,int v)
    {
        int maxl,i;
        for (maxl=min(len[u],len[v]);maxl>0;maxl--)
        {
            bool ok=1;
            for (i=0;i<maxl;i++)
            {
                if (s[v][i]!=s[u][len[u]-maxl+i]) {ok=0;break;}
            }
            if (ok) return maxl;
        }
        return 0;
    }
     
    int ord[50],tot=0;
    bool vis[50];
    char ansch[110][110];
     
    void dfs(int dep)
    {
        if (dep>restm)
        {
            tot++;
            int i,j,now=0;
            for (i=1;i<=restm;i++)
            {
                for (j=LINK[ord[i-1]][ord[i]];j<len[ord[i]];j++)
                {
                    ansch[tot][now++]=s[ord[i]][j];
                    if (now>n) {tot--;return;}
                }
            }
            if (now<n) tot--;
            return;
        }
         
        int i;
        for (i=1;i<=m;i++)
        {
            if ((del[i]) || (vis[i])) continue;
            ord[dep]=i;vis[i]=1;
            dfs(dep+1);
            vis[i]=0;
        }
    }
     
    bool cmp(int p,int q)
    {
        int i;
        for (i=0;i<n;i++)
            if (ansch[p][i]!=ansch[q][i]) return ansch[p][i]<ansch[q][i]; 
    }
     
    int main()
    {
        n=read();m=read();restm=m;
        int i,j,k;
        for (i=1;i<=m;i++) {scanf("%s",s[i]);len[i]=strlen(s[i]);}
        for (i=1;i<=m;i++)
        {
            for (j=1;j<=m;j++)
            {
                if ((del[i]) || (del[j]) || (i==j)) continue;
                if (len[i]<len[j]) continue;
                if (strstr(s[i],s[j])) {del[j]=1;restm--;break;}
            }
        }
        init();
        for (i=1;i<=m;i++)
            if (!del[i]) insert(s[i],i);
        get_fail();
        dp[0][0][0]=1;
        int now=1,pre=0;
        for (i=1;i<=n;i++)
        {
            memset(dp[now],0,sizeof(dp[now]));
            for (j=0;j<=cnt;j++)
            {
                for (k=0;k<(1<<m);k++)
                {
                    if (dp[pre][j][k])
                    {
                        int p;
                        for (p=0;p<26;p++)
                        {
                            int v=point[j].ch[p];
                            dp[now][v][(k|point[v].end)]+=dp[pre][j][k];
                        }
                    }
                }
            }
            now^=1;pre^=1;
        }
        int all=0;
        for (i=1;i<=m;i++)
            if (!del[i]) all|=(1<<(i-1));
        ll ans=0;
        for (i=0;i<=cnt;i++) ans+=dp[pre][i][all];
        printf("%lld
    ",ans);
        if (ans<=42)
        {
            for (i=1;i<=m;i++)
            {
                for (j=1;j<=m;j++)
                {
                    if ((del[i]) || (del[j])) continue;
                    LINK[i][j]=getl(i,j);
                }
            }
            memset(vis,0,sizeof(vis));
            dfs(1);
            for (i=1;i<=ans;i++) ansord[i]=i;
            sort(ansord+1,ansord+1+tot,cmp);
            for (i=1;i<=tot;i++)
            {
                for (j=0;j<n;j++) putchar(ansch[ansord[i]][j]);
                puts("");
            }
        }
        return 0;
    }
    

    bzoj

  • 相关阅读:
    SQL 基础技能提升
    科技领域的assert和deassert的含义
    PDF调出本来存在的书签面板
    什么是事务( Transaction )?
    verilog 和systemverilog的Timing Check Tasks
    PT静态时序分析的三种模式
    useful systemverilog system tasks
    Accellera举措可能导致Verilog标准分化
    验证方法学的发展历程及比较
    PrimeTime 时序分析流程和方法(ZZ)
  • 原文地址:https://www.cnblogs.com/encodetalker/p/10468634.html
Copyright © 2011-2022 走看看