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×),在每个字符串中求出所有既是前缀又是后缀的子串长度。
例如: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;
}