JZOJ 3977 密码破译
2018-01-07 12:08
267 查看
密码破译
Description
给出一个长度为n,由小写字母组成的母串。给出q组询问,每次询问母串的一个子串的关键值。
一个字符串的价值定义为一个最短的T(某个字符串),使得S=TK ,即K个T依次首尾相连连在一起。
则该字符串的关键值即为T的长度。
Data Constraint
n≤500000,m≤2000000Solution
这是一道伪装的水题。题目让我们求母串的一个子串的最短循环节。
接下来给出两个显然的结论(不给出证明了,请读者自行思考)
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); } }
相关文章推荐
- 破译换字式密码
- 杭电 1287 破译密码
- hdu 1287 破译密码
- HDOJ 1287 破译密码
- 厦大C语言上机 1492 破译时间密码
- pku 3749 破译密码
- HDOJ 题目1287 破译密码(暴力)
- 初探密码破译:Metropolis-Hastings算法破解密文
- (Relax ST1.29)POJ 3749 破译密码(将一个字符串按照一定的规则转化成另外一个字符串)
- 学术休假-破译密码
- 史上最牛玩家 数学+密码学破译隐藏任务
- 破译私信挑战QQ的关键密码
- 十个破译密码方法
- 【JZOJ5332】【NOIP2017提高A组模拟8.23】密码
- 破译换字式密码
- 女解码高手王小云:十年破译五部顶级密码(图)
- 杭电 1287 破译密码
- POJ 3749 破译密码 --from lanshui_Yang
- POJ 3749 破译密码
- 破译密码