[codeforces] 633C Spy Syndrome 2

原题

Trie树+dp

首先,我们可以简单的想到一种dp方式,就是如果这一段可以匹配并且可以与前一段接上,那么更新dp[i]为当前字符串的编号,然后倒推就可以得到答案。

但是,显然我们不能O(m)比较,那么怎么办呢?

这时候就可以体现Trie树的意义了,我们在爬Trie树的过程中就可以完成判断所有合法的字符串。当我们可以更新一个dp的时候就break就好了。

#include<cstdio>
#include<cstring>
#include<vector>
#define M 1001000
#define N 10010
using namespace std;
int n,m,dp[M],l[M],cnt=2,now,ll,pos[M];
char s[M],t[M];
vector <int> v;
struct hhh
{
    int son[26],is;
    hhh()
    {
        is=0;
        memset(son,0,sizeof(son));
    }
}edge[M];

void add(int x)
{
    now=1;
    int q;
    for (int i=ll+1;i<=ll+l[x];i++)
    {
    if (t[i]<‘a‘) q=‘a‘-‘A‘;else q=0;
    if (edge[now].son[t[i]-‘a‘+q]) now=edge[now].son[t[i]-‘a‘+q];
    else
    {
        edge[now].son[t[i]-‘a‘+q]=cnt++;
        now=edge[now].son[t[i]-‘a‘+q];
    }
    }
    edge[now].is=x;
}

int main()
{
    scanf("%d",&n);
    scanf("%s",s+1);
    scanf("%d",&m);
    for (int i=1;i<=m;i++)
    {
    scanf("%s",t+ll+1);
    pos[i]=ll+1;
    l[i]=strlen(t+ll+1);
    add(i);
    ll+=l[i];
    }
    dp[0]=1;
    for (int i=1;i<=n;i++)
    {
    now=1;
    for (int j=1;j<=i && now;j++)
    {
        now=edge[now].son[s[i-j+1]-‘a‘];
        if (edge[now].is && dp[i-j])
        {
        dp[i]=edge[now].is;
        break;
        }
    }
    }
    for (int i=n;i>=1;i-=l[dp[i]])
    v.push_back(dp[i]);
    int ss=v.size();
    for (int i=ss-1;i>=0;i--)
    {
    for (int j=1;j<=l[v[i]];j++)
        putchar(t[pos[v[i]]+j-1]);
    putchar(‘ ‘);
    }
    return 0;
}
时间: 2024-08-30 09:50:07

[codeforces] 633C Spy Syndrome 2的相关文章

Codeforces 633C Spy Syndrome 2(DP+Trie树)

题目大概说给一个加密的字符串,加密规则是把原文转化成小写字母,然后各个单词反转,最后去掉空格.现在给几个已知的单词,还原加密的字符串. 和UVa1401一个道理.. 用dp[i]表示加密字符前i个字符都被解密时,最后所用单词编号,为0表示不能被解密 然后转移一个样,从i出发往前在Trie树上跑,看看能否找到不为0的dp[j],而str[j+1]str[j+2]...str[i-1]str[i]是单词 最后输出方案就根据dp里面的值从最后面回溯找到并输出即可 时间复杂度O(加密字符串长*单词最大长

Codeforces 633 C Spy Syndrome 2 字典树

题意:还是比较好理解 分析:把每个单词反转,建字典树,然后暴力匹配加密串 注:然后我就是特别不理解,上面那种能过,而且时间很短,但是我想反之亦然啊 我一开始写的是,把加密串进行反转,然后单词正着建字典树,然后就TLE了,反着写就能过 真是百思不得解,然后我猜测可能是单词数目比较少 #include <cstdio> #include <iostream> #include <cstring> #include <cstdlib> #include <v

【Henu ACM Round #13 E】Spy Syndrome 2

[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 对m个串建立一棵字典树. 然后对主串. 尝试从第一个位置开始.在字典树中尝试匹配 如果匹配到了位置i 就再从位置i+1开始尝试匹配 (这时又重新从根节点开始重新匹配 每次匹配最多只要往下走50步. 写个递归的过程就好. [代码] #include <bits/stdc++.h> using namespace std; const int N = 1e6; const int NN = 1e4; const int M = 1

一些字符串有关的题目

模板可以在上一篇文章中找到. 因为最近都没有做codeforces,所以这篇文章的主要题目来源就是codeforces啦~ 需要这类题目可以在codeforces上找到hashing.string suffix structures之类的标签. 这些题目都是随便点的,所以有些题目和字符串并没有太大的关系 CF653F Paper Task(非常规比赛) 给一个长度为n的由左右括号做成的字符串,求它子串中不同括号序列的个数. (注意不是求是合法括号序列的子串数量,而是不同括号序列个数) 1<=n<

Codeforces Gym 100463E Spies 并查集

Spies Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100463/attachments Description In the aftermath of Canada’s annexation of Pittsburgh tensions have been pretty high between Canada and the US. You have personally been hired

【codeforces 718E】E. Matvey&#39;s Birthday

题目大意&链接: http://codeforces.com/problemset/problem/718/E 给一个长为n(n<=100 000)的只包含‘a’~‘h’8个字符的字符串s.两个位置i,j(i!=j)存在一条边,当且仅当|i-j|==1或s[i]==s[j].求这个无向图的直径,以及直径数量. 题解:  命题1:任意位置之间距离不会大于15. 证明:对于任意两个位置i,j之间,其所经过每种字符不会超过2个(因为相同字符会连边),所以i,j经过节点至多为16,也就意味着边数至多

Codeforces 124A - The number of positions

题目链接:http://codeforces.com/problemset/problem/124/A Petr stands in line of n people, but he doesn't know exactly which position he occupies. He can say that there are no less than a people standing in front of him and no more than b people standing b

Codeforces 841D Leha and another game about graph - 差分

Leha plays a computer game, where is on each level is given a connected graph with n vertices and m edges. Graph can contain multiple edges, but can not contain self loops. Each vertex has an integer di, which can be equal to 0, 1 or  - 1. To pass th

Codeforces Round #286 (Div. 1) A. Mr. Kitayuta, the Treasure Hunter DP

链接: http://codeforces.com/problemset/problem/506/A 题意: 给出30000个岛,有n个宝石分布在上面,第一步到d位置,每次走的距离与上一步的差距不大于1,问走完一路最多捡到多少块宝石. 题解: 容易想到DP,dp[i][j]表示到达 i 处,现在步长为 j 时最多收集到的财富,转移也不难,cnt[i]表示 i 处的财富. dp[i+step-1] = max(dp[i+step-1],dp[i][j]+cnt[i+step+1]) dp[i+st