codeforces 633C. Spy Syndrome 2 trie + dp

题意

间谍通过一些规则吧密信进行了加密。现在需要你对其解密。

加密规则是把密文全部改成小写字母,然后翻转每个单词。并删去空格。

现在给你加密后的文字和字典,要你找出原来的密文。

思路

因为密文的单词是翻转后的,所以我们可以把字典里的单词翻转,存进字典树中。

dp[i]表示i之前是否能组成正确的信息(true)。
dp[j] = dp[i] 当dp[i]为真,并且(i, j-1)能在字典树中找到。

路径还原,其实可以用dp数组来记录路径。

code

#include <bits/stdc++.h>
using namespace std;

int n, m;
char t[10000 + 5];

char w[100000 + 2][1000 + 5];

int dp[10000 + 5];
int pr[10000 + 5];

struct Trie_tree {
    int _p;
    Trie_tree* _ch[26];

    Trie_tree() {
        _p = 0;
        for (int i=0; i<26; i++) {
            _ch[i] = NULL;
        }
    }
};

Trie_tree* root = new Trie_tree();

void insert (Trie_tree* root, char* p, int c) {
    Trie_tree* node = root;
    char* s = p;

    char tmp;

    while (*s) {
        tmp = (*s >= 'a') ? (*s) : (*s - 'A' + 'a');
        if (node->_ch[tmp - 'a'] == NULL) {
            node->_ch[tmp - 'a'] = new Trie_tree();
        }

        node = node->_ch[tmp - 'a'];
        s++;

    }

    node->_p = c;
}


void dfs(int s) {
    if (0 == dp[s]) {
        printf("%s", w[pr[s]]);
        return ;
    }
    dfs(dp[s]);
    printf(" %s", w[pr[s]]);
}


int main () {
    scanf ("%d", &n);
    scanf ("%s", t);

    scanf ("%d", &m);

    for (int i=1; i<=m; i++) {
        scanf ("%s", w[i]);// cout << strlen(w[i]) << endl;
        reverse(w[i], w[i] + strlen(w[i]));// cout << w[i] << endl;
        insert(root, w[i], i);
        reverse(w[i], w[i] + strlen(w[i]));
    }

    memset(dp, -1, sizeof(dp));
    dp[0] = 0;

    for (int i=0; i<n; i++) {
        if (dp[i] == -1) continue;

        Trie_tree* node = root;
        char *p = t + i;
        int _c = 0;

        while (*p) {
            if (node->_ch[*p - 'a'] == NULL) break;
            // cout << *p << endl;

            node = node->_ch[*p - 'a'];
            p++;
            _c++;
            // cout << "-_-";
            if (node->_p != 0) {
                dp[i + _c] = i;
                pr[i + _c] = node->_p;
            }
        }
    }

    // for (int i=0; i<=n; i++) {
    //  printf("%d ", dp[i]);
    // }

    dfs(n); printf("\n");

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值