该题没有限制字母的组成形式,
也没有限定字符串的总串数,猜测是总长度不超过10^6
基本思路:
对能整除长度的循环节进行验证
abcd为例,总长度4,能整除1,2,4.
对长度为1的循环节a,未通过
对长度为2的循环节ab,未通过
对长度为4的循环节abcd,通过
但有顾虑,总长度为1000000能整除的数有几个?会不会太庞大,编程进行验证。
发现能被1000000整除的数有49个,
如长度为1,涉及1000000/1=1000000次查询
长度为2,涉及1000000/2=500000次查询
长度为4,涉及1000000/4=250000次查询
......
编程计算上述49个长度,共涉及2480437次查询,总查询次数(1000000+2480437)=3480437。有了这个数据,对上述 对能整除长度的循环节进行验证 放心了,不会超时。
验证代码如下:
#include <bits/stdc++.h>
int main(){
int n,i,c=0,d=0;
scanf("%d",&n);
for(i=1;i<=n;i++)
if(n%i==0)c++,d+=n/i;
printf("c=%d d=%d\n",c,d);
return 0;
}
输入输出结果如下:
1000000
c=49 d=2480437
正式开始编码。
发现char中的字母有256个,要找大于256的质数,犯难了,索性编个线性筛,杀鸡用牛刀。
找到一个质数257.
线性筛代码如下:
#include <bits/stdc++.h>
#define maxn 10000010
using namespace std;
int prime[maxn],b[maxn],tot;
void findP(int x){
int i,j;
tot=0;
for(i=2;i<=x;i++)b[i]=0;
for(i=2;i<=x;i++){
if(!b[i])prime[++tot]=i;
for(j=1;j<=tot&&prime[j]*i<=x;j++){
b[prime[j]*i]=1;
if(i%prime[j]==0)break;
}
}
}
int main(){
int x,i;
scanf("%d",&x);
findP(x);
for(i=1;i<=tot;i++)printf("%d ",prime[i]);
return 0;
}
对应的输入输出数据如下:
300
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 1
07 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 2
23 227 229 233 239 241 251 257 263 269 271 277 281 283 293
如何检验线性筛的正确性,请注意,2-100这个区间的质数有25个。
AC代码如下:
ybt
POJ
LOJ
AC代码
#include <cstdio>
#include <cstring>
#define maxn 1000010
#define ULL unsigned long long
#define B 257
using namespace std;
char a[maxn];
ULL ah[maxn],n[maxn];
int main(){
int i,j,an,len;
while(1){
scanf("%s",a+1);
if(a[1]=='.')break;
an=strlen(a+1);
n[0]=1;
for(i=1;i<=an;i++)n[i]=n[i-1]*B;//B进制
ah[0]=0;
for(i=1;i<=an;i++)ah[i]=ah[i-1]*B+a[i];//哈希值
for(len=1;len<=an;len++)
if(an%len==0){
for(j=0;j+len<=an;j+=len)//此行j+=len比较难编,注意j是跳跃的
if(ah[j+len]-ah[j]*n[len]!=ah[len])break;
if(j+len>an){
printf("%d\n",an/len);
break;
}
}
}
return 0;
}