[好题][二分][字符串哈希]Checking the Text POJ2758

23 篇文章 0 订阅
22 篇文章 0 订阅

Wind's birthday is approaching. In order to buy a really really fantastic gift for her, Jiajia has to take a boring yet money-making job - a text checker.

This job is very humdrum. Jiajia will be given a string of text what is English letters and he must count the maximum number of letters that can be matched, starting from two position of the current text simultanously. The matching proceeds from left to right, one character by one.

Even worse, sometimes the boss will insert some characters before, after or within the text. Jiajia wants to write a program to do his job automatically, this program should be fast enough, because there are only few days to Wind's birthday.

Input

The first line of input file contains initial text.

The second line contains then number of commands n. And the following n lines describe each command. There are two formats of commands:

I ch p: Insert a character ch before the p-th. if p is larger than the current length of text, then insert at end of the text.

Q i j: Ask the length of matching started from the i-th and j-th character of the initial text, which doesn't include the inserted characters.

You can assume that the length of initial text will not exceed 50000, the number of I command will not exceed 200, the number of Q command will not exceed 20000.

Output

Print one line for each Q command, contain the max length of matching.

Sample Input

abaab
5
Q 1 2
Q 1 3
I a 2
Q 1 2
Q 1 3

Sample Output

0
1
0
3

题意: 有一个初始文本串s,之后有n次操作。若操作为'Q',则读入i,j,输出原始文本串中第i个后缀和第j个后缀的最长公共前缀。若操作为'I',则读入字符ch以及插入位置pos,在第pos个字符前插入字符ch。

分析: 挺恶心的一道题。插入次数比较少,最多200次插入,因此可以暴力维护。接下来有两种做法,一种是后缀数组+rmq,一种是二分+哈希。由于我记的后缀数组模板构造复杂度O(nlogn),st表预处理复杂度O(nlogn),导致最后超时了,如果换成dc3的构造和更优的rmq算法可能能过吧。第二种做法就是二分+哈希了,每次插入字符后都要维护字符串前缀哈希值,在查询操作时二分长度,对于确定的长度用哈希值判等即可。

比较恶心的是卡自然溢出hash精度,卡双hash常数,最后只能单hash取模过的。

最恶心的一点是我在题意中加粗的部分,查询时给的下标是原始字符串的,因此还需要一个数组f来存储映射关系,f[i]表示原始串中第i个字符在最终串中的位置。

具体代码如下: 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <utility>
#include <cmath>
#include <vector>
#include <algorithm>
#define P1 131
using namespace std;

const int maxn = 1e6+10;
const int mod1 = 1e9+7;
int len;
char s[maxn];
int f[maxn];//f数组用来位置映射 
long long h1[maxn], p1[maxn];

inline bool check(int a, int b, int m)
{
	if(((h1[a+m-1]-h1[a-1]*p1[m])%mod1+mod1)%mod1 == ((h1[b+m-1]-h1[b-1]*p1[m])%mod1+mod1)%mod1)
		return true;
	return false;
}

signed main()
{
	p1[0] = 1;
	for(int i = 1; i <= 60000; i++)
		p1[i] = p1[i-1]*P1%mod1;
	scanf("%s", s+1);
	len = strlen(s+1);
	int temp = len;//记录串初始长度 
	for(int i = 1; i <= len; i++)
	{
		f[i] = i;
		h1[i] = (h1[i-1]*P1+s[i])%mod1;//维护哈希值 
	}
	int q;
	cin >> q;
	for(int i = 1; i <= q; i++)
	{
		char ch[2], op[2];
		int pos;
		scanf("%s", op);
		if(*op == 'I')
		{
			scanf("%s%d", ch, &pos);
			if(pos > len)
			{
				s[len+1] = *ch;
				h1[len+1] = (h1[len]*P1 + s[len+1])%mod1;
			}
			else
			{
				for(int j = temp; j >= 1; j--)
				{
					if(pos > f[j])
						break;
					f[j]++;
				}
				for(int j = len+1; j >= pos+1; j--)
					s[j] = s[j-1];
				s[pos] = *ch;
				for(int j = pos; j <= len+1; j++)
					h1[j] = (h1[j-1]*P1 + s[j])%mod1; 
			}
			++len;
		}
		else
		{
			int a, b;
			scanf("%d%d", &a, &b);
			a = f[a], b = f[b];
			int l = 0, r = min(len-a+1, len-b+1), ans = -1;
			while(l <= r)
			{
				int m = l+r>>1;
				if(check(a, b, m))//如果匹配的上 
				{
					ans = m;
					l = m+1;
				}
				else
					r = m-1;
			}
			printf("%d\n", ans);
		}
	}
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值