首页 > 其他分享 >P4407 [JSOI2009] 电子字典 题解

P4407 [JSOI2009] 电子字典 题解

时间:2022-11-10 19:33:06浏览次数:74  
标签:Hash 题解 ll 枚举 一位 插入 电子字典 P4407 字母

题目:P4407

这题差不多就是 P1688 的改版。

参考一下我在 P1688 的做法,我们继续使用 Hash,然后只要考虑如何去重就好了。

于是就有了这个暴力的想法:# 代表修改,@ 代表添加,$ 代表删除

接下来我们来暴力去重。

考虑怎么样会使单词被重复统计。

  1. 在两个相邻且相同的字母中选一个删掉
  2. 在一个字母旁添加一个一模一样的字母
  3. 修改的字符不会被重复统计

然后我们就可以愉快去重了。

对于上面的 1、2 两种情况,考虑只统计连续相同字母中的最后一个字母

具体操作:

  1. 删除
    (1). 插入字典时: 一位一位枚举,遇到连续相同字母时只改最后一位并塞入 Hash。
    (2). 查询时: 所有空位全部插入 $ 并在 Hash 中查询。

  2. 添加
    (1). 插入字典时: 所有空位全部插入 @ 并塞入 Hash 中。
    (2). 查询时: 一位一位枚举,遇到连续相同字母时只改最后一位并在 Hash 中查询。

  3. 修改
    照常枚举。

为什么要这样分类操作?

我们会发现只有在 1(1) 和 2(2) 情况下我们才能确切地知道当前字符串中枚举到的是不是重复字母,而另外两种情况是我们插入的,可以代表任意字符,只插一位会漏掉很多不同字母的情况。

这样操作就可以把重复的筛掉,且不会过多地去掉合法情况,暴力且能 A。

Naive Code:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline ll Min(ll x, ll y){return x < y ? x : y;}
inline ll Max(ll x, ll y){return x > y ? x : y;}
inline ll rd(){
	ll x = 0;bool f = true;char c = getchar();
	while (c < '0' || c > '9'){if (c == '-') f = false; c = getchar();}
	while (c >= '0' && c <= '9'){x = (x<<3) + (x<<1) + (c ^ 48);c = getchar();}
    return f ? x : -x;
}
inline string srd(){
    char c = getchar();string res = "";
    while (c < 'a' || c > 'z')c = getchar();
    while(c >= 'a' && c <= 'z')res += c, c = getchar();
    return res;
}
const int N = 1e4 + 10, M = 1e6 + 7;

class Hash_table{
    private: 

    struct Node{
        int nextt, num;// num就是该状态下的单词个数
        string str;
    }data[N * 60];int head[M + 10], cnt;

    int h(string s){
        int l = s.size();
        int res = 0;
        for(int i = 0; i < l; ++i)
            res = ((res << 3) + (s[i] - 'a') + M) % M;
        return res;
    }

    public: 

    int find(string s){
        int key = h(s);
        for(int i = head[key]; i; i = data[i].nextt)
            if(s == data[i].str)
                return data[i].num;
        return 0;
    }

    void insert(string s){
        int key = h(s);
        for(int i = head[key]; i; i = data[i].nextt){
            if(s == data[i].str){
                data[i].num++;
                return ;
            }
        }
        data[++cnt].nextt = head[key];
        data[cnt].num = 1;
        data[cnt].str = s;
        head[key] = cnt;
        return ;
    }
}H;

int n, m;
string s, tmp, tmp1, tmp2;

int main(){
    n = rd(), m = rd();
    for(int i = 1; i <= n; ++i){
        s = srd();H.insert(s);
        int l = s.size();
        tmp = s;
        for(int j = 0; j < l; ++j){
            tmp[j] = '#';
            H.insert(tmp);
            if(j == l - 1 || s[j] != s[j + 1]){// 只删除最后一个
                tmp[j] = '#';
                H.insert(tmp);
            }
            tmp[j] = s[j];
        }

        if(l < 20){
            for(int j = 0; j <= l; ++j){
                tmp = tmp1 = tmp2 = "";
                for(int k = 1; k <= j; ++k)
                    tmp1 += s[k - 1];
                for(int k = j + 1; k <= l; ++k)
                    tmp2 += s[k - 1];
                tmp += tmp1, tmp += '#', tmp += tmp2;
                H.insert(tmp);
            }
        }
    }
    for(int i = 1; i <= m; ++i){
        s = srd();
        if(H.find(s)){
            printf("-1\n");
            continue;
        }
        int l = s.size(), ans = 0;
        tmp = s;
        for(int j = 0; j < l; ++j){
            tmp[j] = '#';
            ans += H.find(tmp);
            if(j == l - 1 || s[j] != s[j + 1]){// 只添加最后一个
                tmp[j] = '#';
                ans += H.find(tmp);
            }
            tmp[j] = s[j];
        }
        if(l < 20){
            for(int j = 0; j <= l; ++j){
                tmp = tmp1 = tmp2 = "";
                for(int k = 1; k <= j; ++k)
                    tmp1 += s[k - 1];
                for(int k = j + 1; k <= l; ++k)
                    tmp2 += s[k - 1];
                tmp += tmp1, tmp += '#',tmp += tmp2;
                ans += H.find(tmp);
            }
        }
            
        printf("%d\n", ans);
    }
	return 0;
}

标签:Hash,题解,ll,枚举,一位,插入,电子字典,P4407,字母
From: https://www.cnblogs.com/cotsheep/p/16878240.html

相关文章

  • [AGC040F] Two Pieces 题解
    linkSolution这个题真的挺难的。/kk看了一个下午的题解才搞懂。/fn我们发现我们如果设状态\((x,d)\)表示前面的一个点在\(x\),另一个在\(x-d\),那么三种操作相当于:......
  • 题解 P3974【[TJOI2015]组合数学】
    postedon2022-10-2814:11:41|under题解|sourceproblem给出一个网格图,其中某些格子有财宝,每次从左上角出发,只能向下或右走。问至少走多少次才能将财宝捡完。此对......
  • 【题解】【切开字符串】
    P8631[蓝桥杯2015国AC]切开字符串Sol首先问题可以转化为对每个前缀求出本质不同奇回文子串数,和对每个后缀求出本质不同子串数和本质不同奇回文子串数。本质不同子......
  • simpread-(127 条消息) fastAPI 中的跨域问题解决_小童同学_的博客 - CSDN 博客_fasta
    本文由简悦SimpRead转码,原文地址blog.csdn.netCrossOrigin前言前端采用Vue,后端采用fastAPI的CV项目在开发时遇到跨域问题,记录学习过程与解决方案。概念C......
  • 体验 Python 剪辑视频以及相关问题解决, 一劳永逸!
    前言对于使用Python对视频进行剪辑我们最常用的就是Moviepy,我之前也写过一篇​​《必杀技--使用FFmpeg命令快速精准剪切视频》​​,这篇文章单纯使用的是FFmpeg,他是通过......
  • 题解 P8827 [传智杯 #3 初赛] 森林
    本题解提供两种做法。做法一为了叙述方便,先引入\(n\)级母树的概念。定义\(1\)级母树即为该子树被删去前,其所在的原来的完整的树。如下图,以\(5\)为根的一级母树......
  • node -v显示信息 npm -v 不显示信息问题解决
    两个方法:第一个,1.将打开nodejs文件夹(如果你是安装到D盘,就打开D盘!就是nodejs文件所在目录)2.分别右击该文件,点击列表属性,选择安全,编辑,勾选写入,应用,确定。(目的是为了一会要......
  • 2022 icpc 沈阳站 记录(非题解)
    赛前大概是赛前三周才突然知道拥有了比赛机会。赛前训练和vp频率很高,有一段时间cf上都是绿的。比赛的那一周只有一天没在vp,到了周六热身赛我人都有点麻木。(可能正赛也是......
  • 题解 SP11198 【IPAD - Ipad Testing】
    postedon2021-06-0220:59:42|under题解|sourceSP11198是个神题,它考察了选手们的记忆、乱搞、找规律、压行能力。本题题解是乱搞题解,没有证明。下面就由我来解......
  • 题解 P7724 【远古档案馆(Ancient Archive)】
    postedon2021-07-1419:19:57|under题解|source首先我们先算一下网格最多可能有多少种状态,很显然是\(5^4=625\),完全可以暴力搜索。那怎么实现呢?可以使用bfs,以初......