抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

题面

洛谷 P2743


Solution

这题可以用哈希做,也可以用SA做。下面我们分别讲一下两种做法。

哈希

首先,我们把转掉的问题处理掉。我们考虑把原串做差分数组,即用后面那一个减去前面那一个。这样子,我们直接在新的串上找完全相同的两个不可重叠子串即可。 这个,我们考虑先在外面二分一个答案的长度,然后暴力做,从后往前扫,把所有子串都丢到哈希表里面,插入一个新的串之前,就检查一下之前是否有这个串,如果有的话,就检查一下是否满足相隔长度是否大于mid即可。 时间复杂度$O(nlogn)$

后缀数组

这题的后缀数组做法就比较妙了。 首先,我们还是要做差分数组的。 然后,我们还是要求出SA及height的(不会SA的小伙伴可以看这里) 然后,我们仍然是在外面二分答案,然后考虑怎么检查。 因为每个串不可重复,我们可以考虑把height数组分组,我们希望一个组尽可能长,并且组内所有元素的$height>=mid$,这样子,如果这个组里面有两个原数的sa相隔超过mid,则说明这个结果是正确的。 时间复杂度$O(nlogn)$


Code

我写的双模hash,而且没有使用哈希表,用的是set,总复杂度$O(nlog^2n)$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include<iostream>
#include<cstdio>
#include<set>
using namespace std;
const int N=20000+100;
const int E=233;
const int P2=2333333333;
int n;
unsigned long long POW[N];
long long POW2[N],c[N];
void Init()
{
POW2[0]=POW[0]=1;
for(int i=1;i<=n;i++)
POW[i]=POW[i-1]*E,
POW2[i]=(POW2[i-1]*E)%P2;
}
struct rec
{
unsigned long long hash;
long long hash2;
int t;
friend bool operator < (rec a,rec b)
{
if(a.hash==b.hash)
return a.hash2<b.hash2;
return a.hash<b.hash;
}
};
set <rec> record;
bool Check(int ans)
{
record.clear();
unsigned long long hash=0;
long long hash2=0;
for(int i=1;i<=ans;i++)
{
hash=hash+c[i]*POW[ans-i+1];
hash2=(hash2+c[i]*POW2[ans-i+1])%P2;
}
record.insert((rec){hash,hash2,ans});
for(register int i=ans+1;i<n;i++)
{
hash=(hash-c[i-ans]*POW[ans])*E+c[i]*E;
hash2=((((hash2-c[i-ans]*POW2[ans])*E+c[i]*E)%P2)+P2)%P2;
set <rec> :: iterator p=record.lower_bound((rec){hash,hash2,0});
if((*p).hash==hash and (*p).hash2==hash2)
{
if(i-(*p).t>=ans)
return true;
}
else
record.insert((rec){hash,hash2,i});
}
return false;
}
int main()
{
scanf("%d",&n);
for(register int i=1;i<=n;i++)
scanf("%lld",&c[i]);
for(register int i=1;i<n;i++)
c[i]=c[i+1]-c[i];
Init();

int L=4,R=n,mid,ans=0;
while(L<=R)
{
mid=(L+R)>>1;
if(Check(mid)==true)
ans=mid+1,L=mid+1;
else
R=mid-1;
}

if(ans==6) ans++;
printf("%d",ans);
return 0;
}

评论