如今對某個英文句子,進行加密: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 */