• CF#633C Spy Syndrome 2 DP+二分+hash


    Spy Syndrome 2

    题意

    现在对某个英文句子,进行加密:

    1. 把所有的字母变成小写字母
    2. 把所有的单词反过来
    3. 去掉单词之间的空格

    比如:Kira is childish and he hates losing

    加密为ariksihsidlihcdnaehsetahgnisol

    现在给出加密后的句子,以及m个单词(每个单词可以重复使用),输出原来的句子。

    思路

    使用dp[i]表示第i个字母作为句子最后一个单词的开头所在的单词编号。

    dp值为0表示不能组成句子。

    对于每个单词hash一下,按照每个单词的hash值从小到大排序。

    遍历加密后的句子,对于每个i,往前寻找第一个j使得[i,j]为一个单词(最多1000次,单词长度最大为1000),纪录这个单词的编号。

    对于每一个j,使用二分判断所有的单词中是否存在当前的hash值,如果存在那么[i,j]就是一个合法的单词。
    如果dp[j-1]==0,说明第j-1个字符作为最后一个单词的开头不合法,那么[i,j]作为一个单词肯定不合法,跳过。

    然后DFS输出一下。

    这个思路我就是莽一发,竟然没超时685ms

    正解好像是字典树+dfs,不过字典树还没学。

    代码

    #include<bits/stdc++.h>
    #define pb push_back
    using namespace std;
    typedef long long ll;
    const int N=1e5+10;
    const int mod=1e9+7;
    const int inf=0x3f3f3f3f;
    
    int dp[N];
    char s[N];
    struct note
    {
        int id,val;
        char s[1010];
        bool operator <(const note&a) const
        {
            return val<a.val;
        }
    } arr[N],now;
    bool cmp(note a,note b)
    {
        return a.id<b.id;
    }
    void dfs(int pos)
    {
        if(pos==0) return ;
        int len=strlen(arr[dp[pos]].s);
        dfs(pos-len);
        for(int i=0; i<len; i++)
            printf("%c",arr[dp[pos]].s[i]);
        printf(" ");
    }
    int main()
    {
        int lens;
        scanf("%d%s",&lens,s+1);
        int m;
        scanf("%d",&m);
        for(int i=1; i<=m; i++)
        {
            arr[i].val=0;
            scanf("%s",arr[i].s);
            arr[i].id=i;
            int lent=strlen(arr[i].s);
            for(int j=0; j<lent; j++)//计算当前单词的hash值
            {
                int tmp=arr[i].s[j]-'a'+1;
                if(arr[i].s[j]>='A'&&arr[i].s[j]<='Z')
                    tmp+=32;
                arr[i].val=(arr[i].val*26%mod+tmp)%mod;
            }
        }
        sort(arr+1,arr+1+m);
        dp[0]=1;
        for(int i=1; i<=lens; i++)
        {
            int tmp=0;
            for(int j=i; j>max(0,i-1000); j--)//最多遍历1000位
            {
                tmp=(tmp*26%mod+(s[j]-'a'+1))%mod;
                if(!dp[j-1]) continue;//如果dp[j-1]不能组成句子,当前位没有继续的必要
                now.val=tmp;
                int pos=(int)(lower_bound(arr+1,arr+1+m,now)-arr);
                if(pos!=m+1&&arr[pos].val==tmp)
                {
                    dp[i]=arr[pos].id;//纪录单词编号
                    break;
                }
            }
        }
        sort(arr+1,arr+1+m,cmp);
        dfs(lens);
        printf("
    ");
        return 0;
    }
    /*
    7
    ihereht
    3
    HI
    Ho
    there
    */
    
  • 相关阅读:
    webdriver---API---(java版) the fifth part
    【CSP-S2019模拟】题解
    【CSP-S2019模拟】题解
    【洛谷P5113】—魔女的夜宴Sabbat of the witch(分块+基数排序)
    【Codeforces 666 E】—Forensic Examination(广义Sam+线段树合并)
    【洛谷P4081】【USACO17DEC】—Standing Out from the Herd(广义Sam)
    【洛谷P4451】整数的lqp拆分(生成函数)
    【CSP-S 2019模拟】题解
    【Codeforces 335 E】—Counting Skyscrapers
    【Codeforces 793 G】—Oleg and chess(线段树优化建图+最大流)
  • 原文地址:https://www.cnblogs.com/valk3/p/12829746.html
Copyright © 2020-2023  润新知