您的位置:首页 > 健康 > 美食 > 哈希表与离散化(题目)

哈希表与离散化(题目)

2024/12/23 16:58:16 来源:https://blog.csdn.net/Ryan_hsMax/article/details/139448344  浏览:    关键词:哈希表与离散化(题目)

A. 子串判重

题目描述:

给定一个含有 26 个小写英文字母的字符串。有 m 次询问,每次给出 2 个区间,请问这两个区间里的子字符串是否一样?

输入:

第一行输入一个字符串 S 。

第二行一个数字 m,表示 m 次询问。

接下来 m 行,每行四个数字 l1​,r1​,l2​,r2​ ,分别表示此次询问的两个区间,注意字符串的位置从 1 开始编号。

数据范围:

1≤length(S),m,l1​,r1​,l2​,r2​≤1000000。

输出:

对于每次询问,输出一行表示结果。

如果两个子串完全一样,输出 Yes,否则输出 No(注意大小写)。

样例:

输入:

aabbaabb

3

1 3 5 7

1 3 6 8

1 2 1 2

输出:

Yes

No

Yes

代码如下:​​​​​​

字符串哈希问题,注意本题数据量较大,因此不要循环字符串时求字符串长度,如果在循环中求,循环一次,求解一次,效率很低。

#include <bits/stdc++.h>
using namespace std;const int N = 1e6 +10,P = 131;
typedef unsigned long long ULL;
int m;
char s[N];
ULL h[N],p[N];//求子串的哈希
ULL fun(int l,int r){return h[r] - h[l-1] * p[r-l+1];
} int main(){scanf("%s%d",s+1,&m);//下标从1开始取p[0] = 1;//计算次数过多,不用每次循环都求一次长度int len = strlen(s+1); //预处理前缀和,以及p^n for(int i = 1;i <= len;i++){p[i] = p[i-1] * P;h[i] = h[i-1] * P + s[i]-'a'+1;} int l1,r1,l2,r2;while(m--){scanf("%d%d%d%d",&l1,&r1,&l2,&r2);if(fun(l1,r1)==fun(l2,r2)) printf("Yes\n");else printf("No\n");}return 0;
}


B. 前缀和后缀

题目描述:

给定若干由小写字母组成的字符串(这些字符串总长 ≤4×10^{5}),在每个字符串中求出所有既是前缀又是后缀的子串长度。

例如:ababcababababcabab,既是前缀又是后缀的:

ab,abab,ababcabab,ababcababababcabab 。

输入:

输入若干行,每行一个字符串。

输出:

对于每个字符串,输出一行,包含若干个递增的整数,表示所有既是前缀又是后缀的子串长度。

样例:

输入:

ababcababababcabab
aaaaa

输出:

2 4 9 18
1 2 3 4 5

代码如下

#include <bits/stdc++.h>
using namespace std;const int N = 4e5 + 10;
typedef unsigned long long ULL;
ULL h[N],p[N],P = 131;
char s[N];ULL get(int l,int r){return h[r] - h[l-1] * p[r-l+1];
}int main()
{while(scanf("%s",s+1)!=EOF){p[0] = 1;//预处理字符串前缀哈希值 和 p的次方for(int i = 1; s[i]; i++){p[i] = p[i-1] * P;h[i] = h[i-1] * P + (s[i]-'a'+1);}//计算所有可能的长度int len = strlen(s+1);for(int i = 1;i <= len;i++){if(get(1,i)==get(len-i+1,len)) printf("%d ",i);}printf("\n");}return 0;
}

C. 最多子串重复次数

题目描述:

给定若干个长度 ≤106 的字符串,询问每个字符串最多是由多少个相同的子字符串重复连接而成的。如:ababab 则最多有 3 个 ab 连接而成。

输入:

输入若干行(所有行的字符串的长度之和≤107),每行有一个字符串,字符串仅含英语小写字母。特别的,字符串可能为 . 即一个半角句号,此时输入结束。

输出:

对于每行输入,输出一个整数,代表计算的结果。

样例:

输入:

abcd
aaaa
ababab
.

输出:

1
4
3

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N=1e6+10,P=131;
ull h[N],p[N];
char s[N];
int m,len;
ull get(int l,int r){return h[r]-h[l-1]*p[r-l+1];
}
bool check(ull hh,int k){for(int i=k+1;i<=len;i+=k){if(get(i,i+k-1)!=hh) return 0;}return 1;
}
int main(){for(int i;;i++){scanf("%s",s+1);if(s[1]=='.') break;p[0]=1;len=strlen(s+1);for(int i=1;i<=len;i++){p[i]=p[i-1]*P;h[i]=h[i-1]*P+(s[i]-'a'+1);}for(int i=1;i<=len;i++){if(len%i==0){if(check(h[i],i)){printf("%d\n",len/i);break;}}}} return 0;
}

D. 书号管理

题目描述:

图书管理是一件十分繁杂的工作,在一个图书馆中每天都会有许多新书加入。为了更方便的管理图书(以便于帮助想要借书的客人快速查找他们是否有他们所需要的书),我们需要设计一个图书查找系统。

该系统需要支持 2 种操作:

add(x) 表示新加入一本书号为 x 的图书。

find(x) 表示查询是否存在一本书号为 x 的图书。

输入:

第一行包括一个正整数 n,表示操作数。 以下 n 行,每行给出 2 种操作中的某一个指令条,指令格式为:

add x
find x

在书号 x 与指令(add,find)之间有一个隔开,我们保证所有书号都是一个值在 [−109≤x≤109] 之间的整数。

本题 n≤106 。

输出:

对于每个 find(x) 指令,我们必须对应的输出一行 yes 或 no,表示当前所查询的书是否存在于图书馆内。

注意:一开始时图书馆内是没有一本图书的,本题允许加入到图书馆的书号 x 出现重复。

样例:

输入:

8
add 3
add 100006
add 6
find 6
add 100009
find 9
add -100000
find 3

输出:

yes
no
yes

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N=1e6+3;
ull h[N],e[N],ne[N],idx;
int n;
void insert(int x){int v=(x%N+N)%N;idx++;e[idx]=x;ne[idx]=h[v];h[v]=idx;
}
bool query(int x){int v=(x%N+N)%N;for(int i=h[v];i!=0;i=ne[i]){if(e[i]==x) return 1;}return 0;
}
int main(){scanf("%d",&n);char order[10];int x;while(n--){scanf("%s%d",order,&x);if(order[0]=='a') insert(x);else{if(query(x)) printf("yes\n");else printf("no\n");}}return 0;
}

E. 图书管理

题目描述:

图书管理是一件十分繁杂的工作,在一个图书馆中每天都会有许多新书加入。为了更方便的管理图书(以便于帮助想要借书的客人快速查找他们是否有他们所需要的书),我们需要设计一个图书查找系统。

该系统需要支持 2 种操作:

add(s) 表示新加入一本书名为 s 的图书。

find(s) 表示查询是否存在一本书名为 s 的图书。

输入:

第一行包括一个正整数 n,表示操作数。

以下 n 行,每行给出 22 种操作中的某一个指令条,指令格式为:

add s
find s

在书名 s 与指令(add,find)之间有一个空格隔开,我们保证所有书名的长度都不超过 200 。

可以假设读入数据是准确无误的。

本题 n≤30000 。

输出:

对于每个 ����(�)find(s) 指令,我们必须对应的输出一行 yes 或 no,表示当前所查询的书是否存在于图书馆内。

注意:一开始时图书馆内是没有一本图书的。并且,对于相同字母不同大小写的书名,我们认为它们是不同的。

样例:

输入:

4
add Inside C#
find Effective Java
add Effective Java
find Effective Java

输出:

no
yes

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10,M=1e4+10;
int a[N],b[N],c[M];
int n;
int main(){scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);b[i]=a[i];}sort(b+1,b+n+1);int k=unique(b+1,b+n+1)-b-1;int x;for(int i=1;i<=n;i++){x=lower_bound(b+1,b+k+1,a[i])-b;c[x]++;}for(int i=1;i<=k;i++){printf("%d %d\n",b[i],c[i]);}return 0;
}

G. 自动灌溉

题目描述:

农场的有一个用于科学研究的大棚,大棚内有一条笔直的直线,直线的每个整数位置上都种植了一株科研植物,整数位置的范围为 [0,109]。

大棚内设有一个自动灌溉机,会根据各植物检测到的特征数据,对特定位置的植物进行灌溉 。

现从计算机中调取了某一天 N 次灌溉记录。第 i 条灌溉记录有两个数据 Pi​ 和 Xi​,代表为位于 Pi​ 位置的植物,灌溉了 Xi​ 毫升的水。

针对当天的灌溉记录有 M 次询问,第 j 条询问需要计算一个区间 [Lj​,Rj​] 当天的总灌溉量。

请编程计算出 M 次询问,每次的询问结果。

输入:

第 1 行读入 2 个整数 N 和 M;

接下来 N 行,每行读入 2 个整数 P 和 X;

接下来 M 行,每行读入 2 个整数 L 和 R;

输出:

输出 M 行,每行一个整数,代表每次询问的结果。

样例:

输入:

3 4
2 1
8 2
5 3
1 3
2 5
3 8
2 8

输出:

1
4
5
6

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int p[N],x[N],l[N],r[N];
int a[N*3],c[N*3],k=0;
int n,m;
int main(){scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d%d",&p[i],&x[i]);a[++k]=p[i];}for(int i=1;i<=m;i++){scanf("%d%d",&l[i],&r[i]);a[++k]=l[i];a[++k]=r[i];}sort(a+1,a+k+1);k=unique(a+1,a+k+1)-a-1;for(int i=1;i<=n;i++){p[i]=lower_bound(a+1,a+k+1,p[i])-a;c[p[i]]+=x[i];}for(int i=1;i<=k;i++){c[i]+=c[i-1];}for(int i=1;i<=m;i++){l[i]=lower_bound(a+1,a+k+1,l[i])-a;r[i]=lower_bound(a+1,a+k+1,r[i])-a;printf("%d\n",c[r[i]]-c[l[i]-1]);}return 0;
}

H. 程序自动分析

题目描述:

在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足。

考虑一个约束满足问题的简化版本:假设 x1​,x2​,x3​,⋯ 代表程序中出现的变量,给定 n 个形如 xi​=xj​ 或 xi​≠xj​ 的变量相等/不等的约束条件,请判定是否可以分别为每一个变量赋予恰当的值,使得上述所有约束条件同时被满足。例如,一个问题中的约束条件为:x1​=x2​,x2​=x3​,x3​=x4​,x4≠x1​,这些约束条件显然是不可能同时被满足的,因此这个问题应判定为不可被满足。

现在给出一些约束满足问题,请分别对它们进行判定。

输入:

输入的第一行包含一个正整数 t,表示需要判定的问题个数。注意这些问题之间是相互独立的。

对于每个问题,包含若干行:

第一行包含一个正整数 n,表示该问题中需要被满足的约束条件个数。接下来 n 行,每行包括三个整数 i,j,e,描述一个相等/不等的约束条件,相邻整数之间用单个空格隔开。若 e=1,则该约束条件为 xi​=xj​。若e=0,则该约束条件为 xi​≠xj​。

输出:

输出包括 t 行。

输出文件的第 k 行输出一个字符串 YES 或者 NO(字母全部大写),YES 表示输入中的第 k 个问题判定为可以被满足,NO 表示不可被满足。

样例:

输入:

2
2
1 2 1
1 2 0
2
1 2 1
2 1 1

输出:

NO
YES

输入:

2
3
1 2 1
2 3 1
3 1 1
4
1 2 1
2 3 1
3 4 1
1 4 0

输出:

YES
NO

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
struct node{int x,y,e;
}a[N];
int b[N*2],fa[N*2],k;
int n,t;
bool f;
bool cmp(node n1,node n2){return n1.e>n2.e;
}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);
}
void merge(int x,int y){int rx=find(x);int ry=find(y);if(rx!=ry){fa[rx]=ry;}
}
int main(){scanf("%d",&t);while(t--){scanf("%d",&n);for(int i=1;i<=n*2;i++){fa[i]=i;}k=0;for(int i=1;i<=n;i++){scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].e);b[++k]=a[i].x;b[++k]=a[i].y;}sort(b+1,b+k+1);k=unique(b+1,b+k+1)-b-1;sort(a+1,a+n+1,cmp);f=1;for(int i=1;i<=n;i++){a[i].x=lower_bound(b+1,b+k+1,a[i].x)-b;a[i].y=lower_bound(b+1,b+k+1,a[i].y)-b;if(a[i].e==1){merge(a[i].x,a[i].y);}else{if(find(a[i].x)==find(a[i].y)){f=0;break;}}}if(f) puts("YES");else puts("NO");}return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com