CF633C Solution

题目链接

题解

将密文\(t\)反转后,此题便化为一般的字符串匹配。

因为存在对之后状态产生影响的不同方案,可以想到dp:\(dp_i\)表示字符串\(t\)(反转后)前\(i\)项可以匹配的最后一个单词下标(若无法匹配为\(0\))。设单词\(j\)长度为\(a\),如果\(dp[i]>0\)并且存在单词与\(t\)\([i+1,i+a]\)区间匹配,则\(dp[i+a]=j\)。记录最后单词是为了输出路径,以\(i\)减去最后单词的长度即可找到上一状态。

对于字符串匹配的部分,将\(w\)中的单词存入Trie树中,枚举密文\(t\)中的单词起点在Trie树中查询更新即可。时间复杂度为\(O(nw)\)

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N=10010,M=1e5+10,W=1e6+10;
char s[N];
int dp[N],t[W][30],qaq[W],cnt,ans[N],tot;
//t:Trie树,qaq[i]:Trie树中编号为i的叶子节点所对单词下标,cnt:Trie树节点个数
string w[M];
int qwq(char x)//字母编号(忽略大小写)
{
	if(x>='a' && x<='z') return x-'a';
	if(x>='A' && x<='Z') return x-'A';
	return 27;
}
void add(int x,int num,int pos)//插入单词
{
	if(pos>=w[num].size()) {qaq[x]=num; return;}
	int id=qwq(w[num][pos]);
	if(!t[x][id]) t[x][id]=++cnt;
	add(t[x][id],num,pos+1);
}
void query(int pos,int x)//查询
{
	int id=qwq(s[pos]); 
	dp[pos-1]=max(dp[pos-1],qaq[x]);
	if(t[x][id]) query(pos+1,t[x][id]);
}
int main()
{
	ios::sync_with_stdio(0);
	int n,m;
	cin>>n>>s+1>>m; reverse(s+1,s+n+1);
    //reverse:反转 
	for(int i=1;i<=m;i++) {cin>>w[i]; add(0,i,0);}
	dp[0]=1;
	for(int i=1;i<=n+1;i++)
		if(dp[i-1]) query(i,0);
	int x=n;
	while(x) {ans[++tot]=dp[x]; x=x-w[dp[x]].size();}//回溯路径
	for(int i=1;i<=tot;i++) cout<<w[ans[i]]<<" ";
	return 0;
}
posted @ 2021-02-09 15:49  violet_holmes  阅读(79)  评论(0编辑  收藏  举报