题意:

给出n个串,m组询问。每组询问均为一个字符串,询问在初始n个串中是否存在一个串与该询问串恰好只有一个位置不相同。输出YES or NO。

Hash思路:

首先先讲讲Hash的算法,利用bkdr算法将每个字符串hash成一个数值,hash函数如下:

hash: abccac
hash[1] = 0
hash[6] = 0*131^5+1*131^4+2*131^3+2*131^2+0*131+2

此处hash[6]即是这个字符串的hash值,131为seed,即hash种子,然后还要取一个模数,即mod。由此可以发现hash值即是字符串中每一个位置的贡献,所以本题要求恰好只有一个位置不相同,即可以枚举不相同位置,减去原有贡献,加上新贡献即可。然后本题就可以解决,但是由于此题的数据卡的很e xin,所以seed和mod取的不好的话,会被卡成zz。

这里补充一下常见的seed和mod,seed一般取质数,3、5、7、13、131、13131这些均可,mod一般也取质数,1e9+7,1e11+7,1e13+7,1e18+7均可,也可以直接将数据类型取为unsigned long long,即可对2^64-1直接取模。

有一个注意点,在计算过程中,seed*mod不能超过数据类型的最大值,否则相当于在计算过程中又模上了一个不是mod的数,会导致结果错误。

由于本题只有三个字符,所以可以将seed定为3,mod定一个很大的数,类似于三进制。

代码:【代码是双hash,写的比较乱】

#include <cstdio>
#include <iostream>
#include <cstring>
#include <map>
#include <algorithm>
#define rep(i,a,b) for(int i = a; i <= b; i++)
using namespace std;
typedef long long ull;
const int N = 6*1e5+1000;
const ull mod = 1e11+7;
const ull ttp1 = 3;
const ull ttp2 = 5;
int n,m;
ull base[5] = {0,1,2,131313,123};
ull seed1[N],seed2[N];
char s[N];
struct Node{ull a,b;
}gn;
map<Node,int> mp;bool operator == (Node x, Node y)
{if(x.a == y.a && x.b == y.b) return true;else return false;
}bool operator < (Node x, Node y)
{return x.a < y.a;
}int solve(ull hash1, ull hash2)
{int len = strlen(s);// printf("s:%s,len:%d\n",s,len);rep(j,0,len-1){rep(k,0,2){if(s[j]-'a' == k) continue;ull tmp1 = hash1;tmp1 = (tmp1+(-base[s[j]-'a']+base[k])*seed1[len-1-j]%mod)%mod;if(tmp1 < 0) tmp1 += mod;ull tmp2 = hash2;tmp2 = (tmp2+(-base[s[j]-'a']+base[k])*seed2[len-1-j]%mod)%mod;if(tmp2 < 0) tmp2 += mod;gn.a = tmp1, gn.b = tmp2;// printf("k:%d,tmp:%llu\n",k,tmp);if(mp[gn] == 1) return 1;}}return 0;
}int main()
{// printf("mod:%lld\n",mod);mp.clear();seed1[0] = 1;seed1[1] = ttp1;seed2[0] = 1;seed2[1] = ttp2;int _ = 6*1e5+100;rep(i,2,_){seed1[i] = (seed1[i-1]*ttp1)%mod;if(seed1[i] < 0) seed1[i] += mod;seed2[i] = (seed2[i-1]*ttp2)%mod;if(seed2[i] < 0) seed2[i] += mod;}scanf("%d%d",&n,&m);rep(i,1,n){scanf("%s",s);int len = strlen(s);ull hash1 = 0;ull hash2 = 0;rep(j,0,len-1){hash1 = (hash1*ttp1%mod+base[s[j]-'a'])%mod;if(hash1 < 0) hash1+=mod;hash2 = (hash2*ttp2%mod+base[s[j]-'a'])%mod;if(hash2 < 0) hash2+=mod;}// printf("s:%s,hash:%llu\n",s,hash);gn.a = hash1, gn.b = hash2;mp[gn] = 1;}rep(i,1,m){scanf("%s",s);int len = strlen(s);ull hash1 = 0;ull hash2 = 0;rep(j,0,len-1){hash1 = (hash1*ttp1%mod+base[s[j]-'a'])%mod;if(hash1 < 0) hash1+=mod;hash2 = (hash2*ttp2%mod+base[s[j]-'a'])%mod;if(hash2 < 0) hash2+=mod;}if(solve(hash1,hash2))printf("YES\n");else printf("NO\n");}return 0;
}//mod: 1e9+7, seed: 257
//mod: 1e18+3, seed: 3、5
//mod: 1e11+7, seed: 3、5、1313、...
//如果mod*seed会越界的话,那么结果就会错误,因为计算过程中出现了两个seed,多了自动溢出的那个seed

Trie树思路:

本题也可以对n个已知串建立Trie树, 然后对于m个查询串,允许在匹配过程中有一次失配的情况,然后进行dfs搜索即可。详见代码中的query函数。

此处再提一下Trie树的原理,根节点编号为0或1,然后在加入字符串的过程中,每增加一个新节点,就给这个节点编号。在Trie树中,边记录a、b、c等字符,点记录这个节点的信息,比如是否为某一个串的结尾,以及以这个节点为结尾的字符串有多少个等信息。

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define rep(i,a,b) for(int i = a; i <= b; i++)
using namespace std;
const int N = 6*1e5+1000;
const int max_node = 6*1e5+1000;
const int charset = 30;int n,m;
char s[N];struct Trie
{int tot,root,child[max_node][charset];  //root:根节点  tot:节点编号//child[i][j]=k,表示编号为i的节点的第j个孩子是编号为k的节点int flag[max_node];   //是否以某一个字符为结束Trie(){ root = tot = 1;  //根节点编号为1 memset(flag,0,sizeof flag);}    void insert(const char *str){int cur = root;for(int i = 0;str[i];i++){int x = str[i]-'a';if(child[cur][x] == 0)child[cur][x] = ++tot;cur = child[cur][x];}flag[cur] = 1; //记录单词以该点结束 }int query(const char *str, int cur, int pos, int cnt){// printf("str:%s,cur:%d,pos:%d,cnt:%d\n",str,cur,pos,cnt);int x = str[pos]-'a';if(!str[pos]){if(cnt != 1) return 0;else return flag[cur];}else{// if(child[cur][x] == 0) cnt++;if(cnt == 2) return 0;int jud = 0;rep(i,0,2){if(child[cur][i] == 0) continue;if(i != x)jud = (query(str,child[cur][i],pos+1,cnt+1) | jud);elsejud = (query(str,child[cur][i],pos+1,cnt) | jud);// printf("jud:%d\n",jud);if(jud == 1) break;}return jud;}}
}tre;int main()
{scanf("%d %d",&n,&m);rep(i,1,n){scanf("%s",s);tre.insert(s);}rep(i,1,m){scanf("%s",s);if(tre.query(s,1,0,0)) printf("YES\n");else printf("NO\n");}return 0;
}

【Codeforces Round #291 (Div. 2) C】Watto and Mechanism【Trie树、Hash】相关推荐

  1. hash+set Codeforces Round #291 (Div. 2) C. Watto and Mechanism

    题目传送门 1 /* 2 hash+set:首先把各个字符串的哈希值保存在set容器里,然后对于查询的每一个字符串的每一位进行枚举 3 用set的find函数查找是否存在替换后的字符串,理解后并不难. ...

  2. Codeforces Round #737 (Div. 2) D. Ezzat and Grid 线段树动态开点

    传送门 文章目录 题意: 思路: 题意: 思路: 比较套路的一个题,我们维护一个dp[i]dp[i]dp[i]表示到了第iii行能保留的区间最多是多少. 转移比较明显:dp[i]=max(dp[j]) ...

  3. Codeforces Round #716 (Div. 2) D. Cut and Stick 主席树 + 思维

    传送门 文章目录 题意: 思路: 题意: 给你个长为nnn的数组aaa,定义好的区间为这个区间中每个数出现的次数≤⌈n2⌉\le \left \lceil \frac{n}{2} \right \rc ...

  4. CodeForces Round #291 Div.2

    A. Chewbaсca and Number 感觉这道题巨坑,如果题中加粗标出来的输出得是正数算小坑的话.有个巨坑就是 the final number shouldn't start with a ...

  5. Codeforces Round #291 (Div. 2)

    A 简单题 B 简单题 C 求改变一个字母的单词是否出现过 字典树+dfs D k次射击 每次可以把一列都减小1 总共m列 m列都为0就被破坏掉 问最多连续多少个被破坏掉 二分答案 在用数据结构询问某 ...

  6. Codeforces Round #337 (Div. 2) D. Vika and Segments 线段树扫描线

    D. Vika and Segments 题目连接: http://www.codeforces.com/contest/610/problem/D Description Vika has an i ...

  7. Codeforces Round #742 (Div. 2) E. Non-Decreasing Dilemma (线段树维护区间连续问题)

    题意: 操作1:把x位置的数字修改成y. 操作2:查询[l,r]之间不下降序列的个数. 题解: 线段树维护区间和问题 (这是套路,想不到只能说做题少别打我) . 用五个变量进行维护. sum区间总个数 ...

  8. 主席树 | 莫队 ---- Codeforces Round #716 (Div. 2) D. Cut and Stick [主席树or莫队优化] 区间众数问题(静态)

    题目链接 题目大意: 就是给你nnn个数,和q次询问,每次询问给你一个区间[l,r][l,r][l,r],问你把区间里面的数分配成最少多少块,使得块内出现最多次数的数不超过区间长度的一半(除不尽向上取 ...

  9. Codeforces Round #686 (Div. 3) F. Array Partition 二分 + 线段树

    传送门 文章目录 题意: 思路: 题意: 化简一下题意就是求满足max(1,x)=min(x+1,y)=max(y+1,n)max(1,x)=min(x+1,y)=max(y+1,n)max(1,x) ...

  10. Codeforces Round #193 (Div. 2) B. Maximum Absurdity(线段树+思维)

    题目要求我们找到两个长度为 k 的不相交的子段,使得这两个子段之和最大,输出这两个子段的左端点 先将 [k,n] 的长度为 k 的子段和求出来,将其放入线段树中,然后枚举区间 i∈[k,n],使 i ...

最新文章

  1. 测试一下StringBuffer和StringBuilder及字面常量拼接三种字符串的效率
  2. hdu 5521 Meeting(最短路)
  3. .NET开发Windows服务
  4. Silverlight-Visifire图表使用示例发布时空白页面的解决办法
  5. 驱动提取软件_深入分析施耐德工控软件代码执行漏洞
  6. .NET Core IoT 入门指南:(三)使用 I2C 进行通信
  7. 苹果CMS V10 播放记录_苹果cms10怎么更新集数?
  8. 大数据有哪些基本特征
  9. jQuery实现滑动门效果
  10. 乌拉、利用python实现tree命令
  11. 检定规程JJG687- 2008《液态物料定量灌装机》解析
  12. 【转】Latex入门教程
  13. 学渣上手 LaTeX 完成毕业论文
  14. 创意字体设计中主题类别有哪些呢?
  15. 转载好用的小工具 【who-lock-me】
  16. LSTM预测多支股票的收盘价
  17. Postman~做接口测试
  18. 播动师,直播广场,一目了然看到直播态势
  19. SpringMVC 第一篇(SpringMVC入门小案例)
  20. 软件测试之测试用例颗粒度问题

热门文章

  1. 设计模式之美:Builder(生成器)
  2. iso中应用外部资源
  3. Mybatis全局配置文件Configuration.xml详解
  4. 纯php代码进行删除数据操作
  5. linux python tab补全_Linux设置python自动tab自动补全
  6. Python(二十):迭代器、生成器
  7. acrobat 控件可以发布吗_自己能做小程序商城吗?可以发布使用吗
  8. 信用评分卡 (part 3of 7)
  9. 知乎cookies的介绍_Requestium = Requests + Selenium
  10. text无法使用空格 unity_简单的介绍几种在unity中对数据的存储和读档的方法!