ARC060F 题解
题意:给出字符串 \(S\),把 \(S\) 分成若干段,每一段都不存在正周期,求最小段数以及有多少种使得段数最小的分法,第二个数模 \(10^9+7\)。
顶级诈骗题
-
若 \(S\) 不存在正周期,那么答案为 \(1,1\)。
-
若 \(S\) 所有字符相同,那么答案为 \(n,1\)。
-
否则,第一问答案为 \(1\)。
考虑证明。前两个结论显然,证明第三个结论。
- 弱周期引理:若 \(p,q\) 为 \(S\) 的周期(不是正周期),且 \(p+q\le |S|\),那么 \(\gcd(p,q)\) 也是 \(S\) 的周期。
证明:钦定 \(p>q\),根据已知,当 \(i+p\le |S|\) 时,\(s_i=s_{i+p}\);当 \(i-q>0\) 时,\(s_i=s_{i-q}\)。不难发现,由于 \(p+q\le|S|\),对于任意 \(1\le i\le n\),都有一者成立。对于前者,\(s_i=s_{i+p}=s_{i+p-q}\);对于后者,\(s_i=s_{i-q}=s_{i-q+p}=s_{i+p-q}\)。总之能推出 \(s_i=s_{i+p-q}\)。那么 \(p-q\) 也是 \(|S|\) 的周期,这个过程很像更相减损术,然后归纳证明 \(s_i=s_{i+\gcd(p,q)}\)。
对于原结论,证明:
根据已知,\(S\) 存在正周期,设周期长度为 \(p\)。那么我们把 \(S\) 分成 \(S_{1...n-1},S_{n...n}\) 两部分,考虑反证,设 \(S_{1...n-1}\) 存在正周期长度 \(q(q<n-1)\)。
显然 \(p\) 仍然是 \(S_{1...n-1}\) 的一个周期,又由 \(p\) 是 \(S\) 的正周期以及 \(q\) 是 \(S_{1...n-1}\) 的正周期得 \(p\le \frac n2,\space q\le \frac {n-1}2\),显然 \(p+q\le n\),根据弱周期引理,\(\gcd(p,q)\) 也是 \(S_{1...n-1}\) 的一个周期。
设 \(x=\gcd(p,q)\)。已知 \(S_{1...n-1}\) 并不是所有字符相同,所以不存在长度为 \(1\) 的周期,即 \(x>1\),若 \(p=ax,\space q=bx\),而 \(n,n-1\) 分别是 \(p,q\) 的倍数,也都是 \(x\) 的倍数,即 \(x|\gcd(n,n-1)\),而 \(x>1\),相当于 \(\gcd(n,n-1)>1\),矛盾。
故 \(S_{1...n-1}\) 不存在正周期。
对于第二问,我们可以直接枚举两段的分割点,正反跑 \(\text{KMP}\) 预处理每个前/后缀的 \(\text{Border}\)。
时间复杂度 \(O(n)\)。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll maxn=5e5+10;
char s[maxn];
ll n,ans,f1[maxn],f2[maxn];
int main()
{
scanf("%s",s+1); n=strlen(s+1);
ll fl=1;
for(ll i=2;i<=n;i++)
if(s[i]!=s[i-1])
{
fl=0;
break;
}
if(fl)
{
printf("%lld\n1",n);
return 0;
}
for(ll i=2,j=0;i<=n;i++)
{
while(j&&s[j+1]!=s[i]) j=f1[j];
if(s[j+1]==s[i]) f1[i]=++j;
}
f2[n]=f2[n+1]=n+1;
for(ll i=n-1,j=n+1;i;i--)
{
while(j<n+1&&s[j-1]!=s[i]) j=f2[j];
if(s[j-1]==s[i]) f2[i]=--j;
else f2[i]=n+1;
}
if(f1[n]==0||n%(n-f1[n])) printf("1\n1");
else
{
for(ll i=1;i<n;i++)
if((f1[i]==0||i%(i-f1[i]))&&(f2[i+1]==n+1||(n-i)%((n-i)-(n-f2[i+1]+1)))) ++ans;
printf("2\n%lld",ans);
}
return 0;
}

浙公网安备 33010602011771号