• 无限链计数


    1708:无限链计数

    时间限制: 3000 ms         内存限制: 262144 KB

    【题目描述】

    你可以用前t个小写字母来组成两段都无限长的链.

    要求这些链中不能出现n个给定的串中的任何一个,请问有多少个满足条件的不同的无限链呢?

    两个相同的两端均无限长的链A和B需要满足的条件为A[i+k]=B[i]对于任意的i都成立,其中k为任意整数。

    例如t=2,给定串为{ab,ba},那么只有 …aaa…与 …bbb…两个,如果给定串为{ab},则有…aaa…,…bbb…,…bbbbaaa…三个。

    【输入】

    第一行两个整数t和n,含义如题所述。

    接下来n行每行一个字符串表示一个不能出现的串。

    【输出】

    输出一行一个整数表示答案,如果有无限多个输出-1,保证答案不超过231-1


    【输入样例】

    2 2
    ab
    ba

    【输出样例】

    2

    【提示】

    【数据规模与约定】

    对于20%的数据,t≤2,n=1;

    对于另外30%的数据,t≤2;

    对于100%的数据,n≤1000,t≤6,每个给定的串长度不超过10。

    【题解】

    首先建立AC自动机。并对AC自动机求强连通分量。

    发现如果有非简单环,则肯定是-1因为他可以在一个上跑无限圈在到另一个跑任意圈在回来跑无数圈。

    还有就是一条路径上有>=3个环,则-1,(在第一个环上跑无限圈到第二个环跑任意圈,在第三个环跑无数圈)。

    然后就是拓扑排序解决有多少条路径保证开头结尾都是环。

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e4+5;
    int n,m,dfn[N],low[N],cnt;
    char c[12];
    struct trie
    {
        int er[6],fail,pan;
    }a[N];
    inline void insert()
    {
        int len=strlen(c+1),now=0;
        for(int i=1;i<=len;i++)
        {
            if(!a[now].er[c[i]-'a']) a[now].er[c[i]-'a']=++cnt;
            now=a[now].er[c[i]-'a'];
        }
        a[now].pan=1;
    }
    queue <int> que;
    inline void get_fail()
    {
        for(int i=0;i<=n-1;i++)
            if(a[0].er[i])
                que.push(a[0].er[i]);
        while(!que.empty())
        {
            int now=que.front();que.pop();
            a[now].pan|=a[a[now].fail].pan;
            for(int i=0;i<=n-1;i++)
            {
                if(a[now].er[i])
                {
                    a[a[now].er[i]].fail=a[a[now].fail].er[i];
                    que.push(a[now].er[i]);
                }
                else 
                    a[now].er[i]=a[a[now].fail].er[i];
            }
        }
    }
    //aczidongji
    //-----------------------------------------------
    //tarjan
    struct pigu
    {
        int dao,ne;
    }aa[N*10],b[N*10];
    int last1[N],last2[N],top,size1,panh[N],siz,cnt1,size2,st[N],dui[N],bian[N],dian[N],ru[N],f[N],ge[N];
    bool book[N];
    inline void lingjiebiao1(int x,int y)
    {
        aa[++size1].dao=y;
        aa[size1].ne=last1[x];
        last1[x]=size1;
    }
    inline void lingjiebiao2(int x,int y)
    {
        b[++size2].dao=y;
        ru[y]++;
        b[size2].ne=last2[x];
        last2[x]=size2;
    }
    inline void dfs(int now)
    {
        dfn[now]=low[now]=++cnt1;
        book[now]=1;st[++top]=now;
        for(int i=last1[now];i;i=aa[i].ne)
        {
            if(dfn[aa[i].dao]==0)
            {
                dfs(aa[i].dao);
                low[now]=min(low[now],low[aa[i].dao]);
            }
            else
                if(book[aa[i].dao]==1)
                    low[now]=min(low[now],dfn[aa[i].dao]);
        }
        if(low[now]==dfn[now])
        {
            int k;siz++;
            do
            {
                k=st[top--];
                book[k]=0;
                dui[k]=siz;
                dian[siz]++;
            }while(k!=now);
        }
    }
    inline int build_bian()
    {
        for(int i=0;i<=cnt;i++)
        {
            if(a[i].pan==1) continue;
            for(int j=0;j<=n-1;j++)
            {
                if(a[a[i].er[j]].pan) continue;
                lingjiebiao1(i,a[i].er[j]);
            }
        }
        for(int i=0;i<=cnt;i++)
            if(dfn[i]==0&&!a[i].pan) dfs(i);
        for(int i=0;i<=cnt;i++)
            for(int j=last1[i];j;j=aa[j].ne)
                if(dui[i]!=dui[aa[j].dao])
                    lingjiebiao2(dui[i],dui[aa[j].dao]);
                else
                    bian[dui[i]]++;
        for(int i=1;i<=siz;i++)
            if(bian[i]>dian[i])
            {
                cout<<"-1";
                return 0;
            }
            else    
                if(bian[i]==dian[i]) panh[i]=1;
    }
    inline void tuopu()
    {
        for(int i=1;i<=siz;i++) if(ru[i]==0) que.push(i),ge[i]=panh[i];
        while(!que.empty())
        {
            int now=que.front();que.pop();
            if(ge[now]>=3)
            {
                cout<<"-1";
                return;
            }
            if(panh[now]) f[now]++;
            for(int i=last2[now];i;i=b[i].ne)
            {
                f[b[i].dao]+=f[now];
                ru[b[i].dao]--;
                if(ru[b[i].dao]==0) que.push(b[i].dao);
                ge[b[i].dao]=max(ge[b[i].dao],ge[now]+panh[b[i].dao]);
            }
        }
        int ans=0;
        for(int i=1;i<=siz;i++) if(panh[i]) ans+=f[i];
        cout<<ans;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%s",c+1);
            insert(); 
        }
        get_fail();
        if(build_bian()==0) return 0;
        tuopu();
        return 0;
    }
    View Code
  • 相关阅读:
    redis持久化的几种方式
    Spring Cloud基础教程
    微服务实践三: 服务编排
    分库分表的几种常见玩法及如何解决跨库查询等问题
    Spring Cloud微服务开发笔记5——Ribbon负载均衡策略规则定制
    第1章 Python基础-Python介绍&循环语句 练习题&作业
    MySQL中 optimize table '表名'的作用
    Python3 命令行参数
    Python enumerate() 函数
    Python rpartition() 方法
  • 原文地址:https://www.cnblogs.com/betablewaloot/p/12158505.html
Copyright © 2020-2023  润新知