• Gym100221C Forbidden Subwords


    Link
    先建出AC自动机,然后把终止状态去掉,这样Trie图上的一条路径就对应了一个不包含Forbidden Subwords的字符串。
    考虑如何对单向无限的串计数。单向无限的串是一条从根开始的无限长的路径,最后肯定会走到某个scc(自环也是强连通的)。
    如果一个scc包含了不止一个简单环,那么我们就可以在两个环上来回走,答案就是(+infty)
    那么现在所有的scc都是一个简单环。
    如果某个从根出发的路径经过了两个scc,那么就可以在第一个scc上走任意多圈,答案也是(+infty)
    那么现在一条合法的路径就是从根出发经过一些没有自环的单点走到一个scc,然后沿着scc走无限圈。
    此时路径条数就是有限的了,可以在缩点之后的Trie图上求出。
    现在考虑双向无限,相比于单向无限,我们可以比较近似的认为它是从某个scc开始到某个scc结束(可能是同一个)。
    因此第二个判断答案为(+infty)的条件就变成了存在一条经过三个scc路径。
    最长路径和计数都可以在缩点之后的Trie图上求出。
    注意要保留Trie图中的重边来判断是否是简单环。

    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    const int N=10007;
    char str[13];int n,m,cnt,tot,t,top,f,ans,vis[N],fa[N],ch[N][6],bel[N],dfn[N],low[N],stk[N],is[N],tag[N],mx[N],sum[N];
    std::vector<int>e[N],a[N];std::queue<int>q;
    void ins(){int p=0;for(int l=strlen(str+1),i=1,c;i<=l;p=ch[p][c],++i)if(!ch[p][c=str[i]-'a'])ch[p][c]=++cnt;vis[p]=1;}
    void build()
    {
        for(int c=0;c<n;++c) if(ch[0][c]) q.push(ch[0][c]);
        for(int x,c;!q.empty();) for(x=q.front(),q.pop(),vis[x]|=vis[fa[x]],c=0;c<n;++c) ch[x][c]? q.push(ch[x][c]),fa[ch[x][c]]=ch[fa[x]][c]:ch[x][c]=ch[fa[x]][c];
        for(int x=0;x<=cnt;++x) for(int c=0;c<n;++c) if(!vis[ch[x][c]]) e[x].push_back(ch[x][c]);
    }
    void pop(int u)
    {
        ++tot;int s=0;
        do ++s,bel[stk[top]]=tot,a[tot].push_back(stk[top]); while(stk[top--]^u);
        for(int u:a[tot]) for(int v:e[u]) s-=bel[v]==tot;
        s>=0? is[tot]=!s:f=1;
    }
    void tarjan(int u)
    {
        dfn[u]=low[u]=++t,stk[++top]=u;
        for(int v:e[u]) if(!dfn[v]) tarjan(v),low[u]=std::min(low[u],low[v]); else if(!bel[v]) low[u]=std::min(low[u],low[v]);
        if(dfn[u]==low[u]) pop(u);
    }
    void dp(int x)
    {
        if(tag[x]) return; tag[x]=1;
        for(int u:a[x]) for(int v:e[u]) if(bel[v]^x) dp(bel[v]),sum[x]+=sum[bel[v]],mx[x]=std::max(mx[x],mx[bel[v]]);
        if(is[x]) ++mx[x],++sum[x],ans+=sum[x];
    }
    int main()
    {
        freopen("forbidden.in","r",stdin); freopen("forbidden.out","w",stdout);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;++i) scanf("%s",str+1),ins();
        build(),tarjan(0),dp(bel[0]),printf("%d",f||mx[bel[0]]>=3? -1:ans);
    }
    
  • 相关阅读:
    Python lambda 多变量
    Python 的 zip 和 dict 组合 生成新字典
    Solr集群Replication配置与实践(四)
    linux系统搭建zookeeper集群(二)
    linux系统中安装solr搜索引擎(一)
    Solr搜索引擎集群搭建(三)
    CentOS7的yum重装
    安装konga 路由设置
    安装Snipe-IT资产管理系统
    安装GLPI资产管理
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12431273.html
Copyright © 2020-2023  润新知