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
*/
原文地址:https://www.cnblogs.com/valk3/p/12829746.html