【题】【DP(trie维护)】NKOJ3824 解密游戏

本文介绍了一款解密游戏的算法实现,通过构建字典树和动态规划来解决密文匹配问题,旨在寻找最少数量的字典单词组合,使得这些单词能够匹配给定的数字串形式的密文。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

NKOJ3824 解密游戏
时间限制 : - MS 空间限制 : 465536 KB
评测说明 : 2000ms

问题描述
小南和小开特别喜欢玩解密游戏,轮到小南加密的时候,由于他的加密方式过于丧心病 狂,所以小开怎么也不能解密成功,于是她来找你帮忙。 密文是一个长度为 n 的数字串,只由 0~9 之间的数字组成。每个小写字母对应 0~9 之 间的一个数字。小南和小开共同拥有一本字典,字典中有 m 个单词,每个单词长度不超过 50。 明文是一个数字,表示最少用多少个单词首尾拼接在一起,使得拼接而成的这个字符串 可以表示密文(也即相同位置的字符串中字母对应数字跟密文相同)。单词可以重复使用。
输出明文,如果无解的话明文为-1。

输入格式
第一行两个正整数 n,m。
第二行有 26 个数字,每个数字是 0~9 之间的数,分别表示字母 a~z 对应的数字。
第三行是长度为 n 的数字串,表示密文。 接下来 m 行,每行一个小写字母串,表示字典中的一个单词。

输出格式
输出一个整数,表示明文

样例输入 1
10 5
2 2 2 3 3 3 4 4 1 1 5 5 6 6 0 7 0 7 7 8 8 8 9 9 9 0 7325189087
it
your
reality
real
our

样例输出 1
2

样例输入 2
10 5
2 2 2 3 3 3 4 4 1 1 5 5 6 6 0 7 0 7 7 8 8 8 9 9 9 0 4294967296
it
your
reality
real
our

样例输出 2
-1

提示
【数据范围】
对于 30%的数据:1 ≤ n,m ≤ 1000。
对于 100%的数据:1 ≤ n,m ≤ 105。
【样例 1 解释】
我们最少可以用两个单词 reality our,组成的字符串 realityour 去表示密文。
【样例 2 解释】
没有选法使得单词组成的字符串可以表示密文。

来源 wjj

思路:
先全转为数字串。
状态:f[i]表示匹配前i位,且i为结尾的最小子串数。
考虑在密文中依次讨论每一位,从该位出发,往后x位若存在一个子串与题目所给单词匹配则,f[i+x]=min(f[i+x],f[i]+1)
使用字典树存储子串

#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
using namespace std;
const int lenmax=1006;
const int inf=1e9;

int n,m;
int c[27];
char b[lenmax],a[lenmax];
//...............................................
struct trie
{
    int ne[10],len;
    trie(int d=0,int e=0)
    {
        len =e;
        for(int i=0;i<=9;i++) ne[i]=d;
    }
};

#define add push_back(trie())
int now=0;
vector<trie> w(1,trie());

void insert(int len)
{
    int p=0,t;
    for(int i=0;i<len;i++)
    {
        t=c[a[i]-'a'];
        if(w[p].ne[t]!=0) p=w[p].ne[t];
        else 
        {
            w.add;
            now++;
            p=w[p].ne[t]=now;
        }
    }
    w[p].len=len;
}
//...............................................
int dp[lenmax];
int* f;

void dosomething(int k)
{
    int p=0,t;
    for(int i=k+1;i<n;i++)
    {
        t=b[i]-'0';
        p=w[p].ne[t];
        if(p==0) break;
        if(w[p].len!=0) 
        {
            if(k+w[p].len<n) f[k+w[p].len]=min(f[k+w[p].len],f[k]+1);
            else return ;
        }
    }
}
//...............................................

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<26;i++) scanf("%d",c+i);
    scanf("%s",b);
    for(int i=1;i<=m;i++)
    {
        scanf("%s",a);
        insert(strlen(a));
    }
    f=dp+1;
    f[-1]=0;
    for(int i=0;i<n;i++) f[i]=inf;
    for(int i=0;i<n;i++)
    {
        if(f[i-1]==inf) continue;
        dosomething(i-1);
    }
    cout<<(f[n-1]==inf ? -1 : f[n-1]);
}
内容概要:本文详细介绍了在Linux环境下进行C++开发所需掌握的内容,以一个Web多人聊天项目为例,涵盖从开发环境搭建到项目部署的全过程。首先推荐了一个项目地址,该项目支持HTTP请求、Websocket、多房间和多人聊天、MySQL用户信息存储、Redis缓存、json序列化等功能,并建议扩展功能如基于Reactor模型构建HTTP/Websocket服务、仿写MySQL/Redis连接池等。接着介绍了开发环境,包括Ubuntu 20.04、MySQL 8.0、Redis 6.0、gcc/g++ 10.5.0等,并提供了详细的部署步骤,如安装boost库、编译聊天室服务、配置MySQL和Redis等。最后分析了项目架构,包括数据存储(MySQL存储用户信息,Redis存储房间消息和用户cookie)、消息格式(HTTP请求消息和Websocket交互消息)、HTTP/Websocket数据处理流程等。; 适合人群:有一定Linux基础,想深入了解C++开发及网络编程的开发者,尤其是有志于从事Web开发或服务器端开发的技术人员。; 使用场景及目标:①掌握Linux C++开发环境的搭建,包括工具链的安装与配置;②理解并实践HTTP、Websocket等网络协议的应用;③熟悉MySQL、Redis等数据库的使用;④学习如何处理HTTP请求、Websocket交互消息及数据存储;⑤能够独立完成类似Web聊天室的项目开发。; 其他说明:本文不仅提供了理论指导,还给出了具体的实践操作步骤,如编译过程中可能遇到的问及解决方案。对于初学者来说,可以按照文中提供的链接和教程逐步学习,同时鼓励读者根据自身需求对项目进行扩展和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值