【一句话题意】给定一个长为n的字符大小为’A’~'Z’的字符串,有m个询问,每次有两个指针一个指向ai另一个指向bi,逐个字符进行比较并向右移动,直至两个指针所指的字符不同位置或者比较到尽头,输出相同的字符长度。
n
,
m
<
=
100000
n,m<=100000
n,m<=100000
【分析】考虑一种有效的判断一个相同区间大小的算法,(明显是Hash) 。再定义一个倍增数组存从i点出发,向右(1<<j)个字符串的hash值,直接在线乱跑,就可以过了。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL maxn=1e5+1000;
const LL Hkey=29;
char s[maxn];
LL n,m,large;
LL p[maxn][20],h[20];
inline LL pw(LL x,LL p){LL ret=1LL;while(p>0){if(p&1)ret*=x;x*=x,p>>=1;}return x;}
inline void read(LL &x){
x=0;char tmp=getchar();
while(tmp<'0'||tmp>'9') tmp=getchar();
while(tmp>='0'&&tmp<='9') x=(x<<1)+(x<<3)+tmp-'0',tmp=getchar();
}
int main(){
freopen("drunk.in","r",stdin);
freopen("drunk.out","w",stdout);
cin>>n>>m;
scanf("%s",s+1);
for(register LL i=1;i<=n;i++)
p[i][0]=s[i]-'a';
while((1LL<<large)<=n) large++;
large--;
for(register LL i=0;i<large;i++)
h[i]=pw(Hkey,1<<i);
for(register LL j=1;j<=large;j++){
LL d=n-(1LL<<j)+1;
for(register LL i=1;i<=d;i++){
p[i][j]=p[i][j-1]+p[i+(1<<j-1)][j-1]*h[j-1];
}
}
for(register LL i=1;i<=m;i++){
register LL x,y,cnt=0;
read(x),read(y);
for(register LL j=large;j>=0;j--){
if(x+(1LL<<j)-1>n&&y+(1LL<<j)-1>n) continue;
if(p[x][j]==p[y][j]) x+=1LL<<j,y+=1LL<<j,cnt+=1LL<<j;
}
printf("%lld\n",cnt);
}
return 0;
}