1457 Power Strings(POJ2406 loj10035) 被动取模 自然溢出 滚动哈希 无符号整数 B进制数 枚举循环节超时吗

总目录

在线测评地址(ybt)

POJ2406地址(POJ)

在线测评地址(loj)

该题没有限制字母的组成形式,

也没有限定字符串的总串数,猜测是总长度不超过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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值