• 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;
    }
    
  • 相关阅读:
    TreeMap Red-Black tree
    Java实现生产者消费者问题与读者写者问题
    一个对象占用多大内存
    MySQL索引背后的数据结构及算法原理
    Java并发编程与技术内幕:线程池深入理解
    Java Spring 中你不知道的注入方式
    面试中的排序算法总结
    JAVA反射
    StringBuilder与StringBuffer的区别
    Java多线程总结【转】
  • 原文地址:https://www.cnblogs.com/violetholmes/p/14393210.html
Copyright © 2020-2023  润新知