(字典树)D. Double Strings(Codeforces Round #806 (Div. 4))

 

 该说不说,这种树的题真的是不好写而且还不好调试,思路很简单,但是因为是树状结构真的非常考验耐心呀!唉,做了一下午可算是做出来了。但是大家最好还是不要光弄明白思路就不亲手写了,虽然很不好写,但是确实我练习的还不够,多练习一下就会熟了,而且写三个小时代码然后ac的那一刻真的超级爽有木有!

(咱也不知道这个发文助手老是提醒我文章质量不高啥的,真的栓Q,我一点一点敲出来的智慧结晶好嘛!哪里违规了!什么时候CSDN能取消这个傻里傻气的助手啊。。。。。)

题意:t组输入,每组n个字符串,问每个字符串能否由其他n-1个字符串中的任意两个,或者任意一个字符串的两倍构成,若abab可由ab和ab构成,或者a和bab构成。如果第i个字符串能够被组成,就赋值为1,不能的话就赋值为0,将答案0和1构成一个数组整体输出。

思路:因为只由小写字母组成,所以我们很容易想到字典树,首先用n个字符串构建一个字典树,然后将n个字符串依次判断,因为题目给出每个字符串的长度都是小于等于8的(解决本题的重要信息),所以我们可以枚举多种情况,将一个字符串分成前后两部分,如果前一部分在字典树中出现过,就继续看后一部分是否出现过,如果前一部分没有出现过,就增加前一部分的长度,减小后一部分的长度,继续循环,如果前后部分都出现过了,就将1入队,如果遍历了所有情况都没有答案,就将0入队,这样的话时间复杂度就不会很高。

需要注意的点:1.字典树在结构体定义的时候,指针的数组下标要开大一点,否则会rte;

                         2.变量在多次使用前记得更新为初始值。

                         3.注意叶子结点的标记,如果是字符串的结尾就要标记一下。

#include <bits/stdc++.h>

using namespace std;
int i,cnt,j,k,n,m,p,ans;
char s[100010][10],ss[10];
queue <int> q;
struct node
{
    int data;
    struct node *tree[30];//数组大小需要注意噢
    int leef;//叶子节点标记
};
struct node *build(struct node *root)//建字典树
{
    p++;
    if(p>=m)
        return root;
    if(root->tree[s[i][p]-'a'+1]==NULL)
    {
        root->tree[s[i][p]-'a'+1]=new node;
        for(j=1;j<=26;j++)
            root->tree[s[i][p]-'a'+1]->tree[j]=NULL;
            if(p==m-1)
            root->tree[s[i][p]-'a'+1]->leef=1;
            else
        root->tree[s[i][p]-'a'+1]->leef=0;
        root->tree[s[i][p]-'a'+1]=build(root->tree[s[i][p]-'a'+1]);
    }
    else
    {
        if(p==m-1)
            root->tree[s[i][p]-'a'+1]->leef=1;
        root->tree[s[i][p]-'a'+1]=build(root->tree[s[i][p]-'a'+1]);
    }
    return root;

};
int found(struct node *root)
{
    p++;
    if(p>=cnt)
        return 1;
    if(p==cnt-1)
    {
        if(root->tree[ss[p]-'a'+1]!=NULL&&root->tree[ss[p]-'a'+1]->leef==1)
            return 1;
        else
            return 0;
    }
    if(root->tree[ss[p]-'a'+1]!=NULL)
    {
        return found(root->tree[ss[p]-'a'+1]);
    }
    else
        return 0;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        struct node *root=new node;
        root->leef=0;
        for(i=1;i<=26;i++)
        {
            root->tree[i]=NULL;
        }
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            scanf("%s",s[i]);
            m=strlen(s[i]);
            p=-1;
            root=build(root);
        }
        for(i=1;i<=n;i++)
        {
            m=strlen(s[i]);
            cnt=0;
            for(j=0;j<m-1;j++)
            {
                cnt=0;
                for(k=0;k<=j;k++)
                    ss[cnt++]=s[i][k];
                ss[cnt]='\0';
                p=-1;
                    ans=found(root);
                if(ans==0)
                    continue;
                else
                {
                    cnt=0;
                    for(k=j+1;k<m;k++)
                    {
                        ss[cnt++]=s[i][k];
                    }
                    ss[cnt]='\0';
                    p=-1;
                    ans=found(root);
                    if(ans==0)
                        continue;
                    else
                    {
                        q.push(1);
                        break;
                    }
                }
            }
            if(j>=m-1)
            q.push(0);
        }
        while(!q.empty())
        {
            printf("%d",q.front());
            q.pop();
        }
        printf("\n");
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值