描述

给定一个包含N个单词的字典:{W1, W2, W3, ... WN},其中第i个单词Wi有具有一个权值Vi。

现在小Hi要进行M次查询,每次查询包含一个前缀字符串Pi和一个后缀字符串Si。他希望知道同时以Pi为前缀并且以Si为后缀的单词中,权值最大的单词的权值是多少?

假设字典包含"hihocoder"、"hijacker"和"hiker",权值依次是30、20和10。

那么对于查询前缀="hi",后缀="er",答案应为30.

输入

第一行包两个整数N和M。(1 <= N <= M)

以下N行每行包含一个只包含小写字母的字符串Wi和对应的权值Vi。

再之后M行每行包含两个字符串Pi和Si。

对于30%的数据,1 <= N, M <= 100

对于100%的数据,1 <= N, M <= 50000, 1 <= |Wi|, |Pi|, |Si| <= 10, 1 <= Vi <= 100000

输出

输出最大的权值。如果没有符合条件的单词,输出-1。

样例输入

3 2
hihocoder 30
hijacker 20
hiker 10
hi er
hihoco hocoder

样例输出

30
30

初始代码:

思路是前缀查找,找到到Now节点,在Now的每个点(需要是单词尾)向前验证是否满足后缀要求,满足则更新最大值,无则输出-1。

这样显然是超时了,保证试一试的态度写了下。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<memory>
using namespace std;
const int maxn=; char s[maxn];
int ch[maxn][],fa[maxn],id[maxn],num[maxn],cnt,val;
int max(int a,int b){ if(a>b) return a; return b; }
void insert()
{
int Now=,L=strlen(s),x;
for(int i=;i<L;i++){
x=s[i]-'a';
if(!ch[Now][x]) ch[Now][x]=++cnt,fa[cnt]=Now,id[cnt]=x;
Now=ch[Now][x];
}
num[Now]=max(num[Now],val);
}
int Max; char a[],b[];
bool check(int Now)
{
int L2=strlen(b);
for(int i=L2-;i>=;i--){
if(Now==) return false;
if(b[i]-'a'!=id[Now]) return false;
Now=fa[Now];
} return true;
}
void dfs(int Now)
{
if(num[Now]) if(check(Now)) Max=max(Max,num[Now]);
for(int i=;i<;i++) {
if(ch[Now][i])
dfs(ch[Now][i]);
}
}
void query()
{
int Now=,L1=strlen(a),x;
for(int i=;i<L1;i++){
x=a[i]-'a';
if(!ch[Now][x]) { printf("-1\n");return ;}
Now=ch[Now][x];
}
Max=-; dfs(Now);
printf("%d\n",Max);
}
int main()
{
int n,m,i,L1,L2;
scanf("%d%d",&n,&m);
for(i=;i<=n;i++){
scanf("%s%d",s,&val);
insert();
}
for(i=;i<=m;i++){
scanf("%s%s",a,b);
L1=strlen(a);L2=strlen(b);
query();
}
return ;
}

改进:

既然对象是前缀和后缀,显然不需要后缀数组或者后缀自动机(二者对象是任意子串)来完成。还是考虑字典树,想个办法把后缀前缀一起查询了。

具体:

对单词abcd (权值为Val): 它的后缀是d,cd,bcd,abcd。把它的后缀连接到前缀上,成为4个单词(其他的最多也才10个),用'#'连接(后缀数组唱用)

对应     :   d#abcd,cd#abcd,bcd#abcd,abcd#abcd,权值都为Val。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<memory>
using namespace std;
const int maxn=; char s[maxn];
int ch[maxn<<][],num[maxn<<],cnt,Val;
int max(int a,int b){ if(a>b) return a; return b; }
void insert()
{
int L=strlen(s),x;
for(int j=L-;j>=;j--){
int Now=;
for(int i=j;i<L;i++){
x=s[i]-'a';
if(!ch[Now][x]) ch[Now][x]=++cnt;
Now=ch[Now][x];
}
x=;
if(!ch[Now][x]) ch[Now][x]=++cnt;
Now=ch[Now][x];
for(int i=;i<L;i++){
x=s[i]-'a';
if(!ch[Now][x]) ch[Now][x]=++cnt;
Now=ch[Now][x];
num[Now]=max(num[Now],Val);
}
}
}
char a[],b[];
void query()
{
int Now=,L1=strlen(a),L2=strlen(b),x;
for(int i=;i<L2;i++){
x=b[i]-'a';
if(!ch[Now][x]) { printf("-1\n");return ;}
Now=ch[Now][x];
}
Now=ch[Now][];if(!Now) { printf("-1\n");return ;}
for(int i=;i<L1;i++){
x=a[i]-'a';
if(!ch[Now][x]) { printf("-1\n");return ;}
Now=ch[Now][x];
}
printf("%d\n",num[Now]);
}
int main()
{
int n,m,L1,L2;
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
scanf("%s%d",s,&Val);
insert();
}
for(int i=;i<=m;i++){
scanf("%s%s",a,b);
query();
}
return ;
}

HihoCoder1656 : 前缀后缀查询([Offer收割]编程练习赛39)(字典树+小技巧)的更多相关文章

  1. [Offer收割]编程练习赛39

    公平分队 #pragma comment(linker, "/STACK:102400000,102400000") #include<stdio.h> #includ ...

  2. HihoCoder1665方块游戏([Offer收割]编程练习赛40)(线段树)

    时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Ho在玩一款类似俄罗斯方块的游戏.与原版俄罗斯方块不同的是,落下方块都是长度不一的横向长条,并且不能移动也不能变成竖直方 ...

  3. HihoCoder1655 : 第K小最简真分数([Offer收割]编程练习赛39)(唯一分解+容斥定理+二分)(不错的数学题)

    描述 给一个整数N,请你求出以N为分母的最简(既约)真分数中第K小的是多少? 输入 两个整数N个K. 对于30%的数据,1 <= N <= 1000000 对于100%的数据,1 < ...

  4. HihoCoder1654: XY游戏([Offer收割]编程练习赛39)(好久没写搜索)(已经超级简短了)

    描述 如下图所示,在4x4的棋盘上有X和Y两种棋子各若干枚:O表示空格. OXXY YOOX XOOY XOXX 小Hi每次可以选择任意一枚棋子,将它移动到上下左右相邻的空格中. 小Hi想知道最少移动 ...

  5. HihoCoder1653 : 公平分队([Offer收割]编程练习赛39)(贪心)

    描述 小Hi和小Ho在玩一个战争游戏.游戏中2N个战斗单位,其中第i个单位的战斗力是Ai. 现在小Hi和小Ho要各选N个单位组成队伍,当然他们都希望自己队伍的总战斗力越大越好. 为了使分队更加公平,经 ...

  6. 【[Offer收割]编程练习赛 14 A】小Hi和小Ho的礼物

    [题目链接]:http://hihocoder.com/problemset/problem/1505 [题意] [题解] 考虑Meet in the middle. 因为两个数的和不是很大; 直接用 ...

  7. hihocoder [Offer收割]编程练习赛61

    [Offer收割]编程练习赛61 A:最小排列 给定一个长度为m的序列b[1..m],再给定一个n,求一个字典序最小的1~n的排列A,使得b是A的子序列. 贪心即可,b是A的子序列,把不在b中的元素, ...

  8. hihocoder [Offer收割]编程练习赛4

    描述 最近天气炎热,小Ho天天宅在家里叫外卖.他常吃的一家餐馆一共有N道菜品,价格分别是A1, A2, ... AN元.并且如果消费总计满X元,还能享受优惠.小Ho是一个不薅羊毛不舒服斯基的人,他希望 ...

  9. [Offer收割]编程练习赛46

    [Offer收割]编程练习赛46赛后题解 A.AEIOU 分析

随机推荐

  1. LVS-DR,real-server为windows 2008的配置

    LVS-DR,real-server为windows 2008的配置 部署邮件系统负载均衡,采用LVS-DR模式,调度器是一台centos 5.8,real-server是两台windows2008, ...

  2. spring中的异步事件

    这里讲解一下Spring对异步事件机制的支持,实现方式有两种: 1.全局异步 即只要是触发事件都是以异步执行,具体配置(spring-config-register.xml)如下: Java代码   ...

  3. URL Handle in Swift (一) -- URL 分解

    更新时间: 2018-6-6 在程序开发过程之中, 我们总是希望模块化处理某一类相似的事情. 在 ezbuy 开发中, 我接触到了对于 URL 处理的优秀的代码, 学习.改进.记录下来.希望对你有所帮 ...

  4. window+Jira+SQL Server

    window下Jira+SQL Server部署+汉化+破解(亲测2018.5) 网上很多都是jira+mysql部署的文章,由于我现在有需求要用SQL Server数据库,因此就动手试了一下,参考网 ...

  5. 【Atheros】如何禁用载波侦听CSMA和BACKOFF

    无线网络上发包之前都要进行载波侦听,如果未收到ACK,就指数级退避之后重传. 有时候我们为了观察网卡在全力发送数据包时的性能,要禁用CSMA和ACK,这一篇文章先来讨论怎么禁用CSMA,这里提供两种思 ...

  6. IOS --支付宝SDK 分解讲解

    开发在手机端的时候(客户端),我们主要负责客户端(手机端)的开发,所以那些繁琐的到支付宝官网填写商户信息可以留给后台去弄,后台只要把: 1回调地址, 2app的ID, 3商户的私钥(privateKe ...

  7. Android API Guides---Storage Access Framework

    存储訪问架构 Android 4.4系统(API级别19)推出存储訪问框架(SAF).新加坡武装部队变得很easy,为用户在其全部自己喜欢的文件存储提供商的浏览和打开文档,图像和其它文件.一个标准的, ...

  8. java常用的基础容器

    1 Vector and ArrayList 它们都是可以随机访问的.它们的区别是Vector是线程安全的,而ArrayList不是线程安全的. 2 HashMap的底层实现机制 2.1 底层数据结构 ...

  9. Netty聊天室-源码

    目录 Netty聊天室 源码工程 写在前面 [百万级流量 聊天室实战]: [分布式 聊天室] [Spring +Netty]: [Netty 原理] 死磕 系列 [提升篇]: [内力大增篇]: 疯狂创 ...

  10. Android笔记之使用ImageView加载网络图片以及保存图片到本地并更新图库

    ImageView显示网络图片 findViewById(R.id.btnLoad).setOnClickListener(new View.OnClickListener() { @Override ...