醉酒(drunk)

11 篇文章 0 订阅
3 篇文章 0 订阅

【一句话题意】给定一个长为n的字符大小为’A’~'Z’的字符串,有m个询问,每次有两个指针一个指向ai另一个指向bi,逐个字符进行比较并向右移动,直至两个指针所指的字符不同位置或者比较到尽头,输出相同的字符长度。
n , m &lt; = 100000 n,m&lt;=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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值