字符串哈希与字典树
Description
给定N个字符串(第i个字符串长度为Mi,字符串内包含数字、大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串。
Input
输入,第一行一个N
接下来N行每行包含一个字符串
接下来N行每行包含一个字符串
Output
输出不同字符串的个数
Sample Input
5
abc
aaaa
abc
abcc
12345
Sample Output
4
#include <iostream> #include<algorithm> #include<string> using namespace std; typedef unsigned long long ull; const ull mod1=1e9+7,mod2=1e9+3,k=131; struct has { ull x,y; }a[100001]; ull hash1(string s) { ull len=s.size(); ull ans=0; for(ull i=0;i<len;i++) { ans=(ans*k+(ull)s[i])%mod1; } return ans; } ull hash2(string s) { ull len=s.size(); ull ans=0; for(ull i=0;i<len;i++) { ans=(ans*k+(ull)s[i])%mod2; } return ans; } bool cmp(has a,has b) { return a.x>b.x; } int main() { int n; string s; cin>>n; int ans=0; for(int i=1;i<=n;i++) { cin>>s; a[i].x=hash1(s); a[i].y=hash2(s); } sort(a+1,a+n+1,cmp); for(int i=1;i<=n;i++) { if(a[i].x!=a[i+1].x||a[i].y!=a[i+1].y) ans++; } cout<<ans<<endl; return 0; }
Description
HHM在阅读一篇文章,他想找出来一个单词的频率,也就是这个单词在文章中出现了几次。聪明的你赶快帮帮他
Input
输入包含多组数据。
输入文件的第一行有一个整数,代表数据组数。接下来是这些数据,以如下格式给出:
第一行是单词W,一个由{'A','B','C',...,'Z'}中字母组成的字符串,保证1<=|W|<=10000(|W|代表字符串W的长度)
第二行是文章T,一个由{'A','B','C',...,'Z'}中字母组成的字符串,保证|W|<=|T|<=1000000。
输入文件的第一行有一个整数,代表数据组数。接下来是这些数据,以如下格式给出:
第一行是单词W,一个由{'A','B','C',...,'Z'}中字母组成的字符串,保证1<=|W|<=10000(|W|代表字符串W的长度)
第二行是文章T,一个由{'A','B','C',...,'Z'}中字母组成的字符串,保证|W|<=|T|<=1000000。
Output
对每组数据输出一行一个整数,即W在T中出现的次数。
Sample Input
3
BAPC
BAPC
AZA
AZAZAZA
VERDI
AVERDXIVYERDIAN
Sample Output
1
3
0
HINT
字符串哈希思路
#include<stdio.h> #include<string.h> #include<iostream> #define ll unsigned long long using namespace std; ll hash[1000005],x,cf[1000005]; char a[1000005]; void read(ll &s,int &l) { s=l=0; char c=getchar(); while(!(c>='A'&&c<='Z')) { c=getchar(); } while(c>='A'&&c<='Z') { l++; s*=27; s+=c-'A'+1; c=getchar(); } } ll ask(int i,int j) { return hash[j]-hash[i-1]*cf[j-i+1]; } void work() { int i,l1,l2,s=0; read(x,l1); scanf("%s",a+1); l2=strlen(a+1); hash[1]=a[1]-'A'+1; for(i=2;i<=l2;i++) { hash[i]=hash[i-1]*27+a[i]-'A'+1; } for(i=1;i<=l2-l1+1;i++) { if(ask(i,i+l1-1)==x) { s++; } } printf("%d\n",s); } int main() { int t,i; for(cf[0]=1,i=1;i<=1000000;i++) { cf[i]=cf[i-1]*27; } scanf("%d",&t); while(t--) { work(); } return 0; }
Description
HMM最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀).
Input
输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给HMM统计的单词,一个#代表单词表的结束.第二部分是一连串的提问,每行一个提问,每个提问都是一个字符串.
Output
对于每个提问,给出以该字符串为前缀的单词的数量.
Sample Input
banana band bee absolute acm # ba b band abc
Sample Output
2
3
1
0
#include <stdio.h> #include <string.h> #include <iostream> using namespace std; struct node{ int num; node* next[26]; node() { num=0; memset(next,0,sizeof(next)); } }; node* root=new node(); node* rt; int id,len; void bulit(string str) { rt=root; len=str.size(); for(int i=0;i<len;i++) { id=str[i]-'a'; if(rt->next[id]==NULL) rt->next[id]=new node(); rt=rt->next[id]; rt->num++; } } int query(string str) { rt=root; len=str.size(); for(int i=0;i<len;i++) { id=str[i]-'a'; if(rt->next[id]==NULL) return 0; rt=rt->next[id]; } return rt->num; } int main() { char str[100]; while(gets(str)) { if(str[0]=='#')break; build(str); } while(gets(str)) { printf("%d\n",querry(str)); } return 0; }
Description
HHM和SY做游戏,SY给HHM一个集合,集合包含了N个整数,随后SY向HHM发起M次询问,每次询问包含一个整数S,之后HHM需要在集合中
找到一个正整数K,使得K与S的异或结果最大。HHM向你请求帮助
找到一个正整数K,使得K与S的异或结果最大。HHM向你请求帮助
Input
输入包含若干组测试数据,每组测试数据包含若干行。
输入的第一行是一个整数T(T < 10),表示共有T组数据。
每组数据的第一行输入两个正整数N,M(<1=N,M<=100000),接下来一行,包含N个正整数,代表 Zeus 的获得的集合,之后M行,每行一个正整数S,代表 Prometheus 询问的正整数。所有正整数均不超过2^32。
输入的第一行是一个整数T(T < 10),表示共有T组数据。
每组数据的第一行输入两个正整数N,M(<1=N,M<=100000),接下来一行,包含N个正整数,代表 Zeus 的获得的集合,之后M行,每行一个正整数S,代表 Prometheus 询问的正整数。所有正整数均不超过2^32。
Output
对于每组数据,首先需要输出单独一行”Case #?:”,其中问号处应填入当前的数据组数,组数从1开始计算。
对于每个询问,输出一个正整数K,使得K与S异或值最大。
对于每个询问,输出一个正整数K,使得K与S异或值最大。
Sample Input
2
3 2
3 4 5
1
5
4 1
4 6 5 6
3
Sample Output
Case #1:
4
3
Case #2:
4
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+10; typedef long long LL; int ch[32 * maxn][2]; LL value[32 * maxn]; int node_cnt; inline void init() { node_cnt = 1; memset(ch[0],0,sizeof(ch)); } inline void Insert(LL x) { int cur = 0; for(int i = 32;i >= 0;--i) { int idx = (x >> i) & 1; if(!ch[cur][idx]) { memset(ch[node_cnt],0,sizeof(ch[node_cnt])); ch[cur][idx] = node_cnt; value[node_cnt++] = 0; } cur = ch[cur][idx]; } value[cur] = x; } inline LL Query(LL x) { int cur = 0; for(int i = 32;i >= 0;--i) { int idx = (x >> i) & 1; if(ch[cur][idx ^ 1]) cur = ch[cur][idx ^ 1]; else cur = ch[cur][idx]; } return value[cur]; } int main() { int t; cin>>t; int d=1; while(t--) { int n,m; scanf("%d%d",&n,&m); int i; init(); for(i=1;i<=n;i++) { LL x; scanf("%lld",&x); Insert(x); } printf("Case #%d:\n",d); for(i=1;i<=m;i++) { LL x; scanf("%lld",&x); printf("%lld\n",Query(x)); } d++; } return 0; }