zoukankan      html  css  js  c++  java
  • bzoj4713: 迷失的字符串

    Description

    有一棵n个节点的大树,上面每条边有一个小写字符。
    对于任意两个不同的点u,v,我们可以在树上找到u出发到v终止的唯一的一条最短路径,并将沿途经过的边上的字符依次写下来,得到一个字符串。
    对于一个字符串,如果存在这样一个点对(u,v),使得它们路径上的字符串与其完全匹配,那么我们就称这个字符串属于这棵树。
    现在有m个迷失的字符串,请你写一个程序帮助判断每一条字符串是否属于这棵树。

    Input

    第一行包含一个正整数n(2<=n<=30000),表示树的点数。
    接下来n-1行每行包含两个正整数a,b和一个小写字符c(1<=a,b<=n,a!=b),表示a点到b点之间有一条无向的树边,上面写着字符c。
    接下来一行包含一个正整数m(1<=m<=30000),表示迷失的字符串的个数。
    接下来m行,每行一个由小写字符组成的字符串,分别表示每个迷失的字符串。
    输入数据保证所有迷之的字符串的长度之和不超过30000。

    Output

    包含m行,对于第i行,如果在树上可以找到第i个字符串,输出YES,否则输出NO。
    对单独一个串可以dp,f[w][i]表示从下往上走到w这条边,是否能匹配到第i个字符,合并原串和反串的答案可以确定原串是否在树上出现,复杂度为O(n*串长)
    可以用bitset优化,同时对所有串进行dp,复杂度降为O(n*总串长/32),可以通过此题
    #include<bits/stdc++.h>
    typedef unsigned int u32;
    typedef u32 bits[945];
    const int N=30007;
    int n,m;
    int es[N*2],enx[N*2],ev[N*2],e0[N],ep=2,ls[N];
    char s0[N];
    int p1=1,p2=0,mx;
    bits v1[26],v2[26],u1[26],u2[26],f1[N],f2[N],ans,ans1,ans2;
    void set1(bits a,u32 x){a[x>>5]|=1<<(x&31);}
    u32 test(bits a,u32 x){return a[x>>5]>>(x&31)&1;}
    void ors(bits a,bits b){for(int i=0;i<=mx;i+=2)a[i]|=b[i],a[i+1]|=b[i+1];}
    void chk(bits a,bits b,bits c){for(int i=0;i<=mx;i+=2)ans[i]|=a[i]&b[i],ans[i+1]|=a[i+1]&b[i+1];}
    void cal1(bits a,bits v,bits u){
        for(int i=mx;i;--i)a[i]=(a[i]<<1|a[i-1]>>31)&v[i]|u[i];
        a[0]=a[0]<<1&v[0]|u[0];
    }
    void cal2(bits a,bits v,bits u){
        a[mx+1]=0;
        for(int i=0;i<=mx;++i)a[i]=(a[i]>>1|a[i+1]<<31)&v[i]|u[i];
    }
    void dfs(int w,int pa,int c=-1){
        for(int i=e0[w];i;i=enx[i]){
            int u=es[i];
            if(u!=pa){
                dfs(u,w,ev[i]);
                chk(f1[w],f2[u],ans);
                chk(f2[w],f1[u],ans);
                ors(f1[w],f1[u]);
                ors(f2[w],f2[u]);
            }
        }
        if(c==-1)return;
        cal1(f1[w],v1[c],u1[c]);
        cal2(f2[w],v2[c],u2[c]);
        ors(ans1,f1[w]);
        ors(ans2,f2[w]);
    }
    int main(){
        scanf("%d",&n);
        for(int i=1,a,b;i<n;++i){
            char c;
            scanf("%d%d %c",&a,&b,&c);
            es[ep]=b;enx[ep]=e0[a];ev[ep]=c-'a';e0[a]=ep++;
            es[ep]=a;enx[ep]=e0[b];ev[ep]=c-'a';e0[b]=ep++;
        }
        scanf("%d",&m);
        for(int i=0;i<m;++i){
            scanf("%s",s0+1);
            int l=strlen(s0+1);
            set1(u1[s0[1]-'a'],++p1);
            ls[i]=p1;
            for(int i=2;i<=l;++i)set1(v1[s0[i]-'a'],++p1);
            for(int i=1;i<l;++i)set1(v2[s0[i]-'a'],++p2);
            set1(u2[s0[l]-'a'],++p2);
        }
        ls[m]=p1+1;
        mx=p1/32+2;
        dfs(1,0);
        for(int i=0;i<m;++i){
            u32 d=test(ans1,ls[i+1]-1)|test(ans2,ls[i]-1);
            for(int j=ls[i];j<ls[i+1]-1;++j)d|=test(ans,j);
            puts(d?"YES":"NO");
        }
        return 0;
    }
  • 相关阅读:
    MySQL/MariaDB数据库的多表查询操作
    Mariadb/MySQL多实例实战
    Mariadb/MySQL生产环境的my.cnf配置示例
    Mariadb/MySQL数据库单表查询基本操作及DML语句
    Mariadb/MySQL安装方式实战篇
    MySQL数据库扫盲篇
    数据库分类及基础概念
    Docker的系统资源限制及验正
    Docker Private Registry 常用组件
    Dockerfile详解
  • 原文地址:https://www.cnblogs.com/ccz181078/p/6489144.html
Copyright © 2011-2022 走看看