hihoCoder 1261 String Problem II 【字典树 + DFS】

本文介绍了一道复杂的字符串匹配问题,通过构建Trie树并使用DFS算法解决三种不同的查询:添加、修改及删除字符来匹配目标字符串。提供了完整的AC代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#1261 : String Problem II

Time Limit:50000ms
Case Time Limit:5000ms
Memory Limit:512MB

Description

We have a set of strings S which contains N distrinct strings.

We have also M queries, each query with a string w, asking you three questions:

1. Output the three strings with the smallest index among all strings in S which can be obtained by adding exactly two characters to w.

2. Output the three strings with the smallest index among all strings in S which can be obtained by modifying no more than two characters of w.

3. Output the three strings with the smallest index among all strings in S which can be obtained by deleting exactly two characters of w.

The character can be added anywhere including before the head and after the tail.

All strings only contain lowercase letters.

Input

First line with two integers N and M, denoting the number of strings in S and the number of queries.

The following N lines, the i-th line giving the i-th string in S whose index is i.

THe following M lines, the i-th line giving the i-th query string.

Data Limit:

N,M<=10000

The sum of length of strings in S <=100000

The sum of length of all query strings <=100000

Output

For each query, output three lines with three numbers on each line indicating the three indexes in a increasing order.

If there are less than three strings meeting the requirements, output -1.

For example, if the strings meeting the requirements are 1 and 2, you should ouput 1 2 -1.

Sample Input
5 5
dsxmlkxp
asxglqkdxp
asxgavxp
asxglp
sxglkx
kebvpyky
hjpntqft
asxglkxp
polbmzgq
jdczlmtd
Sample Output
-1 -1 -1
-1 -1 -1
-1 -1 -1
-1 -1 -1
-1 -1 -1
-1 -1 -1
2 -1 -1
1 3 -1
4 5 -1
-1 -1 -1
-1 -1 -1
-1 -1 -1
-1 -1 -1
-1 -1 -1
-1 -1 -1

题意:给定一个保护N个模式串的集合S和M次查询,每次查询给出一个字符串str,问

1,在串str任意位置增加2个字符能够得到的模式串,找到三个下标最小的,升序输出3个下标,不够3个时输出-1。

2,串str最多修改2个字符能够得到的模式串,找到三个下标最小的,升序输出3个下标,不够3个时输出-1。

3,在串str任意位置删除2个字符能够得到的模式串,找到三个下标最小的,升序输出3个下标,不够3个时输出-1。


思路:建trie树,然后就是DFS。这里坑了好久。。。

第一种情况:当遍历到串str的末尾时,即使增加的字符不够2个,还是可以沿着trie边继续DFS的——只需在末尾前增加一个和末尾相同的字符即可。

第二种情况:当遍历到串str的末尾时,如果修改的字符不超过2个,是不能继续沿着trie边继续DFS的。

第三种情况:当遍历到串str的末尾时,如果删除的字符不够2个,也是不能继续沿着trie边继续DFS的。对于这种情况,我们是可以停留在trie的某个节点上通过删除str的字符继续DFS的。


AC代码:


#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <string>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define MAXN (100000+10)
#define MAXM (500000)
#define Ri(a) scanf("%d", &a)
#define Rl(a) scanf("%lld", &a)
#define Rf(a) scanf("%lf", &a)
#define Rs(a) scanf("%s", a)
#define Pi(a) printf("%d\n", (a))
#define Pf(a) printf("%.2lf\n", (a))
#define Pl(a) printf("%lld\n", (a))
#define Ps(a) printf("%s\n", (a))
#define W(a) while(a--)
#define CLR(a, b) memset(a, (b), sizeof(a))
#define MOD 1000000007
#define LL long long
#define lson o<<1, l, mid
#define rson o<<1|1, mid+1, r
#define ll o<<1
#define rr o<<1|1
#define PI acos(-1.0)
using namespace std;
bool vis[10001];
struct Trie
{
    int next[MAXN][30], L, root, id[MAXN];
    int newnode()
    {
        for(int i = 0; i < 26; i++)
            next[L][i] = -1;
        id[L++] = -1;
        return L-1;
    }
    void init()
    {
        L = 0;
        root = newnode();
    }
    void Insert(char *s, int ID)
    {
        int u = root, v;
        for(int i = 0; s[i]; i++)
        {
            int v = s[i] - 'a';
            if(next[u][v] == -1)
                next[u][v] = newnode();
            u = next[u][v];
        }
        id[u] = ID;
    }
    int ans1, ans2, ans3;
    void Update(int ID)
    {
        int a[4];
        a[0] = ans1 == -1 ? INF : ans1;
        a[1] = ans2 == -1 ? INF : ans2;
        a[2] = ans3 == -1 ? INF : ans3;
        a[3] = ID;
        sort(a, a+4);
        ans1 = a[0] == INF ? -1 : a[0];
        ans2 = a[1] == INF ? -1 : a[1];
        ans3 = a[2] == INF ? -1 : a[2];
        vis[ID] = true;
    }
    void DFS(int u, int use, int pos, char *s, int op)
    {
        switch(op)
        {
            case 1: if(!s[pos] && use == 2)
                    {
                        if(id[u] != -1 && !vis[id[u]])
                            Update(id[u]);
                    }
                    else //if(use <= 2)
                    {
                        for(int i = 0; i < 26; i++)
                        {
                            if(next[u][i] == -1) continue;
                            if(s[pos] == 'a' + i)
                                DFS(next[u][i], use, pos+1, s, op);
                            if(use < 2)
                                DFS(next[u][i], use+1, pos, s, op);
                        }
                    }
                    break;
            case 2: if(!s[pos])// && use <= 2)
                    {
                        if(use <= 2 && id[u] != -1 && !vis[id[u]])
                            Update(id[u]);
                    }
                    else
                    {
                        //if(!s[pos+1]) break;
                        for(int i = 0; i < 26; i++)
                        {
                            if(next[u][i] == -1) continue;
                            if(s[pos] == 'a' + i)
                                DFS(next[u][i], use, pos+1, s, op);
                            else if(use < 2)
                                DFS(next[u][i], use+1, pos+1, s, op);
                        }
                    }
                    break;
            case 3: if(!s[pos]) //&& use == 2)
                    {
                        if(use == 2 && id[u] != -1 && !vis[id[u]])
                            Update(id[u]);
                    }
                    else
                    {
                        //if(!s[pos+1]) break;
                        for(int i = 0; i < 26; i++)
                        {
                            if(next[u][i] == -1) continue;
                            if(s[pos] == 'a' + i)
                                DFS(next[u][i], use, pos+1, s, op);
                            //else if(use < 2)
                            //    DFS(u, use+1, pos+1, s, op);
                        }
                        if(use < 2)
                            DFS(u, use+1, pos+1, s, op);
                    }
        }
    }
};
Trie tree;
char str[MAXN];
void solve(int op)
{
    CLR(vis, false); tree.ans1 = tree.ans2 = tree.ans3 = -1;
    tree.DFS(tree.root, 0, 0, str, op);
    printf("%d %d %d\n", tree.ans1, tree.ans2, tree.ans3);
}
int main()
{
    int N, M;
    while(scanf("%d%d", &N, &M) != EOF)
    {
        tree.init();
        for(int i = 0; i < N; i++)
        {
            Rs(str);
            tree.Insert(str, i+1);
        }
        W(M)
        {
            Rs(str);
            solve(1); solve(2); solve(3);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值