BZOJ 2803 Poi2012 Prefixuffix Hash

题目大意:给定一个字符串S,求一个最长的L(L*2<=n),使S长度为L的前缀和长度为L的后缀循环同构

一开始我的想法是枚举L,判断长度为L的前缀和长度为L的后缀的所有循环同构的哈希值之和是否相等

但是很快我发现这做法是扯淡- - 因为一个字符串所有循环同构的哈希值之和等于这个字符串所有字符ASCII码之和乘上(BASE^len+BASE^(len-1)+...+BASE^2+BASE+1)

然后我在想能不能考虑修改一下哈希函数呢?

比如给每个字符一个BASE,定义一个字符串的哈希值为以字符串开头字符的BASE值为进制的RK哈希……

结果下来数据发现卡自然溢出哈希的那个abbabaab对我的算法效果良好- -

尼玛连abbabacbaabab这种简单的字符串都能卡掉我的代码QAQ

最后…… 膜拜题解…… http://blog.csdn.net/zeyu_king/article/details/42521093

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 1001001
#define BASE 131
#define MOD 45119
using namespace std;
int n,ans,f[M>>1];
char s[M];
int hash[M],power[M];
int Get_Hash(int l,int r)
{
	int len=r-l+1;
	return (hash[r]-hash[l-1]*power[len]%MOD+MOD)%MOD;
}
int main()
{
	int i;
	cin>>n;
	scanf("%s",s+1);
	for(power[0]=1,i=1;i<=n;i++)
	{
		hash[i]=(hash[i-1]*BASE+s[i])%MOD;
		power[i]=power[i-1]*BASE%MOD;
	}
	for(i=n>>1;i;i--)
	{
		f[i]=min(f[i+1]+2,(n>>1)-i+1);
		while( f[i]>0 && Get_Hash(i,i+f[i]-1) != Get_Hash(n-i+1-f[i]+1,n-i+1) )
			f[i]--;
	}
	for(i=1;i<=n>>1;i++)
		if( Get_Hash(1,i-1) == Get_Hash(n-i+2,n) )
			ans=max(ans,i+f[i]-1);
	cout<<ans<<endl;
	return 0;
}

顺便附上我被abbabaab卡掉并且就算卡不掉也会TLE的Hash代码- -

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 1001001
using namespace std;
typedef unsigned long long ll;
const ll bases[26]={31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151};
int n,ans;
char s[M];
ll l1[26],l2[26],r1[26],r2[26],lsum[26],rsum[26],lbases[26],rbases[26];
ll Quick_Power(ll x,int y)
{
	ll re=1;
	while(y)
	{
		if(y&1) re*=x;
		x*=x; y>>=1;
	}
	return re;
}
int main()
{
	int i,j;
	cin>>n;
	scanf("%s",s+1);
	for(i=1;i<=n>>1;i++)
	{
		int x1=s[i]-'a';
		int x2=s[n-i+1]-'a';
		if(i!=1)
		{
			int y2=s[n-i+2]-'a';
			r1[y2]-=rsum[y2];
			r1[x2]+=rsum[x2];
			rbases[y2]-=Quick_Power(bases[y2],i-2);
			rbases[x2]+=Quick_Power(bases[x2],i-2);
		}
		bool flag=true;
		for(j=0;j<26;j++)
		{
			if(j==x1) lbases[j]+=Quick_Power(bases[j],i-1);
			(rbases[j]*=bases[j])+=(j==s[n-i+1+(i!=1)]-'a');
			(l1[j]*=bases[j])+=x1*lbases[j];
			r1[j]+=x2*rbases[j];

			if(l1[j]+l2[j]!=r1[j]+r2[j])
				flag=false;
		}

		if(flag) ans=i;

		for(j=0;j<26;j++)
		{
			(lsum[j]*=bases[j])+=x1;
			rsum[j]+=x2*Quick_Power(bases[j],i-1);
			if(j==s[i+1]-'a') l2[j]+=lsum[j];
			(r2[j]+=(j==s[n-i+1]-'a')?rsum[j]:0)*=bases[j];
		}
	}
	cout<<ans<<endl;
	return 0;
}
时间: 2024-10-30 07:41:54

BZOJ 2803 Poi2012 Prefixuffix Hash的相关文章

【BZOJ2803】[Poi2012]Prefixuffix 结论题

[BZOJ2803][Poi2012]Prefixuffix Description 对于两个串S1.S2,如果能够将S1的一个后缀移动到开头后变成S2,就称S1和S2循环相同.例如串ababba和串abbaab是循环相同的.给出一个长度为n的串S,求满足下面条件的最大的L:1. L<=n/22. S的L前缀和S的L后缀是循环相同的. Input 第一行一个正整数n (n<=1,000,000).第二行n个小写英文字母,表示串S. Output 一个整数,表示最大的L. Sample Inpu

bzoj 2802: [Poi2012]Warehouse Store 题解

[原题] 2802: [Poi2012]Warehouse Store Time Limit: 10 Sec  Memory Limit: 64 MBSec  Special Judge Submit: 94  Solved: 54 Description 有一家专卖一种商品的店,考虑连续的n天. 第i天上午会进货Ai件商品,中午的时候会有顾客需要购买Bi件商品,可以选择满足顾客的要求,或是无视掉他. 如果要满足顾客的需求,就必须要有足够的库存.问最多能够满足多少个顾客的需求. Input 第一

BZOJ 2795: [Poi2012]A Horrible Poem( hash )

...字符串hash. #include<bits/stdc++.h> using namespace std; typedef unsigned long long ull; const int maxn = 500009; const ull P = 1000173169; char S[maxn]; int check[maxn], prime[maxn], N = 0, n; ull H[maxn], K[maxn]; void init() { memset(check, 0, si

【BZOJ2803】【Poi2012】Prefixuffix hash+推性质

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/45768837"); } 题解: 首先我们如果设原串为串[ 1,n ] 然后 fi 表示串[ i+1,n?i ]中最长的串长使得串[ i+1,i+fi ]==串[n?i?fi+1,n?i] 这时存在一个性质 fi?1<=fi+2

Bzoj 2789: [Poi2012]Letters 树状数组,逆序对

2789: [Poi2012]Letters Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 278  Solved: 185[Submit][Status][Discuss] Description 给出两个长度相同且由大写英文字母组成的字符串A.B,保证A和B中每种字母出现的次数相同. 现在每次可以交换A中相邻两个字符,求最少需要交换多少次可以使得A变成B. Input 第一行一个正整数n (2<=n<=1,000,000),表示字符串的长度

BZOJ 3790 神奇项链 hash/后缀自动机+贪心

Description 母亲节就要到了,小 H 准备送给她一个特殊的项链.这个项链可以看作一个用小写字母组成的字符串,每个小写字母表示一种颜色. 为了制作这个项链,小 H 购买了两个机器.第一个机器可以生成所有形式的回文串,第二个机器可以把两个回文串连接起来,而且第二个机器还有一个特殊的性质:假如一个字符串的后缀和一个字符串的前缀是完全相同的,那么可以将这个重复部分重叠.例如:aba和aca连接起来,可以生成串abaaca或 abaca. 现在给出目标项链的样式,询问你需要使用第二个机器多少次才

bzoj 1014 LCP 二分 Hash 匹配

求同一字符串的两个后缀的最长公共前缀. 将字符串按位置放到Splay中维护(每个节点还维护一下该子树的hash),然后二分前缀的长度,用splay计算出指定范围的hash,按hash是否相等来判断是否相同. 一开始是将字符串看成26进制,加上unsigned long long的自然溢出来计算哈希,但这样Wa掉了,改成27进制就AC了,但我还不知道为什么,望明者相告,谢. 1 /***********************************************************

BZOJ 2085 [Poi2010]Hamsters Hash+倍增floyd

题意:链接 方法: Hash+倍增floyd 解析: 首先这个BZ的无脑翻译我真是受不了. 加俩条件 所有串的长度总和不超过100000,并且对于任意不同子串A,B,A不包含于B,B不包含于A. 然后可以做题了. 首先,我们可以暴力hash搞出来如果i串后面接j串则需要增加多少长度. 这个n非常的小所以直接开数组记录. 然后就是倍增floyd了. 至于前半部分为什么是复杂度可以接受的. 参见PoPoQQQ的证明,总之我们要求的 ∑∑(min(leni,lenj))的函数的最大化时,复杂度是O(l

BZOJ 3198 Sdoi2013 spring Hash+容斥原理

题目大意:给定n个元素,每个元素是一个六元组,求有多少对元素满足相同的位置恰好有k个 首先对于恰好有K个这种东西果断考虑容斥原理 我们2^6枚举相同的位置 恰好有k个元素相同的对数=至少有k个位置相同的对数-至少有k+1个位置相同的对数+至少有k+2个位置相同的对数-- 但是我们计数时会发现一些问题 比如下面这组样例显然是0: 2 3 1 2 3 4 5 5 1 2 3 4 6 6 但是这一对元素被加了C(4,3)次,只被减掉了C(4,4)次 因此我们将公式改成这样: 恰好有k个元素相同的对数=