[二分][hash]最长公共子串

1251: 最长公共子串

Time Limit: 5 Sec   Memory Limit: 128 MB
Submit: 76   Solved: 15
[ Submit][ Status][ Web Board]

Description

给定2个字符串,求这两个字符串的最长公共子串。

Input

第一行一个正整数T<=10代表输入数据个数
对于每组输入数据,
有两行字符串(每个字符串的长度小于100000,且该字符串的所有字母都是小写字母)

Output

输出最长公共子串的长度

Sample Input

2abcdecdyeshowmuchiloveyoumydearmotherreallyicannotbelieveityeaphowmuchiloveyoumydearmother

Sample Output

227

HINT

Source

srssyd



用到两个hash。预处理出字符串前缀的hash,可以用O(1)时间复杂度得到任意子串的hash。

由于答案具有单调性(一个公共子串的子串仍是公共子串),因此可以二分答案。

检验的时候将A串中长度为mid的所有子串放进hashTable中(将hash值放进去),再枚举B中长度为mid的所有子串,在hashTable中查询。

时间复杂度O(nlgn)


#include 
#include 
#include 
using std::min;
using std::max;

typedef unsigned long long ull;
const ull seed = 31;
void makehash(char* str,ull* hash,int len)
{
	ull _hash = 0;
	for (int i=len-1;i>=0;i--)
	{
		_hash = _hash * seed + str[i]-'a'+1;
		hash[i] = _hash;
	}
}



struct node
{
	ull v;
	node* next;
};

const int Mod = 3131313;
const int maxlen = 100010;

struct HashTable
{
	node pool[maxlen];
	node* head[Mod];
	int top;
	int version;
	int time[Mod];

	HashTable() { top = version = 0; memset(pool,0,sizeof pool); memset(head,0,sizeof head);memset(time,0,sizeof time);}

	void insert(ull v)
	{
		int hash = v%Mod;
		if (time[hash] < version)
		{
			time[hash] = version;
			head[hash] = 0;
		}
		for (node* vv=head[hash];vv;vv=vv->next)
		{
			if (vv->v == v)
				return;
		}
		top ++;
		pool[top].v = v;
		pool[top].next = head[hash];
		head[hash] = &pool[top];
	}

	bool query(ull v)
	{
		int hash = v%Mod;
		if (time[hash] < version)
		{
			head[hash] = 0;
			return false;
		}
		for (node* vv=head[hash];vv;vv=vv->next)
		{
			if (vv->v == v)
				return true;
		}
		return false;
	}

	void clear()
	{
		version ++;
		top = 0;
	}
};
HashTable table;

char str1[maxlen];
char str2[maxlen];
int len1,len2;
ull hash1[maxlen];
ull hash2[maxlen];
ull pow[maxlen];

ull gethash(ull* hash,int i,int l)
{
	return hash[i] - hash[i+l] * pow[l];
}

bool ok(int mid)
{
	table.clear();
	for (int i=0;i


你可能感兴趣的:(ACM)