如今对某个英文句子,进行加密:c++
好比:Kira is childish and he hates losing
加密
加密为ariksihsidlihcdnaehsetahgnisol
spa
如今给出加密后的句子,以及m个单词(每一个单词能够重复使用),输出原来的句子。code
使用dp[i]
表示第i个字母做为句子最后一个单词的开头所在的单词编号。cdn
dp
值为0表示不能组成句子。排序
对于每一个单词hash一下,按照每一个单词的hash值从小到大排序。get
遍历加密后的句子,对于每一个i,往前寻找第一个j使得[i,j]
为一个单词(最多1000次,单词长度最大为1000),纪录这个单词的编号。hash
对于每个j,使用二分判断全部的单词中是否存在当前的hash值,若是存在那么[i,j]
就是一个合法的单词。
若是dp[j-1]==0
,说明第j-1个字符做为最后一个单词的开头不合法,那么[i,j]
做为一个单词确定不合法,跳过。it
而后DFS输出一下。class
这个思路我就是莽一发,居然没超时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("\n"); return 0; } /* 7 ihereht 3 HI Ho there */