CF633C 字符串

1 CF633C 字符串

2 题目描述

时间限制 \(2s\) | 空间限制 \(256M\)

在观察了 \(Spy Syndrome\) 的结果后,\(Yash\) 发现他的方法有问题。他现在相信像 \(Siddhant\) 这样的超级间谍不会使用像凯撒密码那样的简单、古老的密码。经过了几周对 \(Siddhant\) 句子的观察,\(Yash\) 确定了一种新的加密技术。

对于给定的句子,加密处理为:

  • 将句子的所有字母转换为小写;
  • 把句子的每个单词都反转;
  • 去掉句子中的所有空格。

例如,把句子 \(“Kira\space is\space childish\space and\space he\space hates\space losing”\) 加密后得到的字符串是 \(“ariksihsidlihcdnaehsetahgnisol"\)

现在,\(Yash\) 得到了一个长度为 \(n\) 的加密后的字符串 \(t\) 和有 \(m\) 个字符串的单词列表。帮助他找出任何只使用列表中的单词组成的原始句子。注意,任何给定的单词都可以在句子中多次使用。

数据范围:\(1 ≤ n ≤ 10000, 1 ≤ m ≤ 100000\)

3 题解

如果我们将 \(t\) 这个字符串反转,那么我们的字符串还要倒着去匹配,十分麻烦。因此我们可以考虑将输入的那 \(m\) 个字符串反转去原串中匹配,但是不能在输入时直接将原串翻转,否则会很难在输出时找到原串。

我们接下来来想算法:很显然,我们要找到匹配方案,我们就要借助于 \(trie\) 树。这道题的思路与 \(L\) 语言这道题十分相似,只是多了一个输出路径。具体细节就是设 \(dp_i\) 表示从第 \(1\) 位到第 \(i\) 位是否存在一种字符串组合方式可以没有重叠和空白地组成 \(t\)。然后用 \(ans\) 数组记录每一个 \(dp\) 值为 \(1\) 的位置中上一个字符串结尾的位置和当前这个字符串在那 \(m\) 个字符串中的编号。字典树的用法就是帮助查看到哪一位会出现字符串的结尾,以确定整个字符串。

输出答案时从第 \(n-1\) 位开始慢慢往前跳转即可。

4 代码(空格警告):

#include <iostream>
#include <cstring>
using namespace std;
const int N = 1000100;
int n, m, tot, p, cnt;
int tre[N][30], ep[N], dp[N];
char n1;
string s;
string t[N];
pair<int, int> ans[N];
int ans1[N];
void insert(string x, int pos)
{
    p = 0;
    for (int i = x.length()-1; i >= 0; i--)
    {
        n1 = x[i];
        if (n1 >= 'A' && n1 <= 'Z') n1 += 32;
        if (!tre[p][n1 - 'a']) tre[p][n1 - 'a'] = ++tot;
        p = tre[p][n1 - 'a'];
    }
    ep[p] = pos;
}
int main()
{
    cin >> n >> s >> m;
    for (int i = 1; i <= m; i++)
    {
        cin >> t[i];
        insert(t[i], i);
    }
    for (int i = 0; i < n; i++)
    {
        if (i == 0 || dp[i-1])
        {
            p = 0;
            for (int j = i; j < n; j++)
            {
                n1 = s[j];
                if (!tre[p][n1 - 'a']) break;
                p = tre[p][n1 - 'a'];
                if (ep[p])
                {
                    dp[j] = 1;
                    ans[j] = make_pair(i-1, ep[p]);
                }
            }
        }
    }
    p = n-1;
    while (p >= 0)
    {
        ans1[++cnt] = ans[p].second;
        p = ans[p].first;
    }
    for (int i = cnt; i >= 1; i--) cout << t[ans1[i]] << " ";
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-02-24 20:50  David24  阅读(68)  评论(0编辑  收藏  举报