您的位置:首页 > 其它

JZOJ 3977 密码破译

2018-01-07 12:08 267 查看

密码破译

Description

给出一个长度为n,由小写字母组成的母串。

给出q组询问,每次询问母串的一个子串的关键值。

一个字符串的价值定义为一个最短的T(某个字符串),使得S=TK ,即K个T依次首尾相连连在一起。

则该字符串的关键值即为T的长度。

Data Constraint

n≤500000,m≤2000000

Solution

这是一道伪装的水题。

题目让我们求母串的一个子串的最短循环节。

接下来给出两个显然的结论(不给出证明了,请读者自行思考)

1、串T有一个长度为Len循环节的充要条件为T的前N–Len位与后N–Len位是一样的。

2、若一个长度为Len的前缀不是T的循环节,那么Len的所有约数肯定也不是可行的循环节长度。

有了以上两个结论这题就好做了。

一开始设它的ans为子串的长度Len,枚举Len的所有质因子,假设枚举到当前的质因子为p,若ans/p是一个可行的循环节长度,那么就让ans变成ans/p,这样做显然是对的。

至于判断两个子串是否相同,可以用hash O(1)判断。(为了防卡我打了双hash)

质因子可以用线筛预处理好。

由于每个质因子都大于等于2,所以Len的质因子个数不会超过log2 Len。

所以总的复杂度为O(m log n)。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

#define fo(i,j,l) for(int i=j;i<=l;++i)
#define fd(i,j,l) for(int i=j;i>=l;--i)

using namespace std;
typedef long long ll;
const ll N=52e4,k1=23,k2=29,shit=666,F_word=168;
const ll m1=1e9+7,m2=998244353,m3=1004535809;
char s
;
ll s1
,s2
,j1
,j2
,n1
,n2
;
bool bz
;
int from
,ss
,n,q;

inline ll ksm(ll o,ll t,ll mo)
{
ll y=1;
for(;t;t>>=1,o=o*o%mo)
if(t&1)y=y*o%mo;
return y;
}

inline int read()
{
int o=0; char ch=' ';
for(;ch<'0'||ch>'9';ch=getchar());
for(;ch>='0'&&ch<='9';ch=getchar())o=o*10+ch-48;
return o;
}

ll get(int a,int b)
{
ll k1=(s1[b]-s1[a-1]+m1*2)*n1[a]%m1;
ll k2=(s2[b]-s2[a-1]+m2*2)*n2[a]%m2;
return (k1*shit+k2*F_word)%m3;
}

int main()
{
cin>>n;
scanf("%s",s+1);
s1[1]=s2[1]=s[1]-97; j1[1]=j2[1]=1;
fo(i,2,n)
{
j1[i]=j1[i-1]*k1%m1;
j2[i]=j2[i-1]*k2%m2;
s1[i]=(s1[i-1]+j1[i]*(s[i]-97))%m1;
s2[i]=(s2[i-1]+j2[i]*(s[i]-97))%m2;
}
n1
=ksm(j1
,m1-2,m1);
n2
=ksm(j2
,m2-2,m2);
fd(i,n-1,1)n1[i]=n1[i+1]*k1%m1,n2[i]=n2[i+1]*k2%m2;
n1[0]=n2[0]=1;
int o=0;
fo(i,2,n)
{
if(!bz[i])ss[++o]=i,from[i]=i;
fo(j,1,o){
if(i*ss[j]>n)break;
from[i*ss[j]]=ss[j];
bz[i*ss[j]]=true;
if(i%ss[j]==0)break;
}
}
cin>>q;
fo(i,1,q){
int le=read(),ri=read();
int len=ri-le+1;
int k=len,ans=k;
for(;k!=1;k/=from[k])
if(ans%from[k]==0)
if(get(le,ri-ans/from[k])==get(le+ans/from[k],ri))ans/=from[k];
printf("%d\n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: