Codeforces Round #291 (Div. 2) C - Watto and Mechanism 字符串

【题意】给n个字符串组成的集合,然后有m个询问(0 ≤ n ≤ 3·105, 0 ≤ m ≤ 3·105) ,每个询问都给出一个字符串s,问集合中是否存在一个字符串t,使得s和t长度相同,并且仅有一个字符不同。(字符串总长度为6·105),所有字符只有a,b,c。

 

【题解】因为只有三种字符,用Trie最合适。先把n个字符串插入到Trie中。然后每读入一个字符串,首先枚举差异字符的位置,依次替换为另外两种字符,并检查是否合法。如果合法就直接输出YES。

显然每替换一个字符就从头检查一遍太浪费时间,所以保存字典树中差异字符位置的指针,每次从该位置开始检查即可。

 

我一开始是直接处理n个字符串,枚举差异字符的位置,分别替换后加入到字典树中。但是这样做会耗费相当多的空间,空间复杂度是指数级别(3^len)。MLE或者RE。但是一直返回的是WA7,QAQ找了半天错。。

还有一种方法时使用字符串哈希,但是如果运气不好的话,会出现冲突,然后WA掉,这次比赛很多人跪在了这里

#include<bits/stdc++.h>
#define eps 1e-9
#define FOR(i,j,k) for(int i=j;i<=k;i++)
#define MAXN 1000005
#define MAXM 40005
#define INF 0x3fffffff
using namespace std;
typedef long long LL;
int i,j,k,n,m,x,y,T,ans,big,cas,num,len;
bool flag;
char s[1000005];

struct Trie
{
    int ch[1000005][26];
    int val[1000005];
    int size;
    Trie()
    {
        size=1;
        memset(ch[0],0,sizeof(ch[0]));
        val[0]=0;
        val[1]=0;
    }
     
    int idx(char c)
    {
        return c-'a';
    }
     
    void insert(char *s,int v)
    {
        int u=0,len=strlen(s);
        for (int i=0;i<len;i++)
        {
            int c=idx(s[i]);
            if (!ch[u][c])
            {
                memset(ch[size],0,sizeof(ch[size]));
                val[size]=0;
                ch[u][c]=size++;
            }
            u=ch[u][c];
        }
        val[u]=v;
    }
    
    bool exist(char *s)
    {
        int u=0,len=strlen(s);
        for (int i=0;i<len;i++)
        {
            int c=idx(s[i]);
            
            for (int j=0;j<3;j++)
            {
                if (c==j || ch[u][j]==0) continue;
                int u2=ch[u][j];
                flag=true;
                for (int k=i+1;k<len;k++)
                {
                    int c=idx(s[k]);
                    if (!ch[u2][c]) 
                    {
                        flag=false;
                        break;
                    }
                    u2=ch[u2][c];
                }
                if (flag && val[u2]) 
                {
                    return true;
                }
            }
            
            if (!ch[u][c])
            {
                return false;
            }
            u=ch[u][c];
        }
        return false;
    }
} tree;

int main()
{
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;i++)
    {
        scanf("%s",s);
        tree.insert(s,1);
    }
    for (i=1;i<=m;i++)
    {
        scanf("%s",s);
        if (tree.exist(s)) puts("YES");
        else puts("NO");
    }
        
    return 0;
}

 

                                                                                                                                                             

转载于:https://www.cnblogs.com/zhyfzy/p/4293041.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值