POJ_2635_The Embarassed Cryptographer_同余定律

A题就外放小苹果666。


题意:

密码学背景,给一个大数(10^100),由两个素数相乘得到,给一个10^6以内的l,问这个大数最小的因数是否小于l。


Input

The input consists of no more than 20 test cases. Each test case is a line with the integers 4 <= K <= 10 100 and 2 <= L <= 10 6. K is the key itself, a product of two primes. L is the wanted minimum size of the factors in the key. The input set is terminated by a case where K = 0 and L = 0.

Output

For each number K, if one of its factors are strictly less than the required L, your program should output "BAD p", where p is the smallest factor in K. Otherwise, it should output "GOOD". Cases should be separated by a line-break.


这个题要素数,所以肯定先用筛法打个素数表,然后对每个大数,循环素数,判断是否能被当前素数整除。10^6之前的素数只有10^5级别个,常数比较大,最多20组数据略坑,素数整除尽量控制在50以内。

首先,要做到判断整除需要用到同余定律,百度百科:


同余公式也有许多我们常见的定律,比如相等律,结合律,交换律,传递律….如下面的表示:
1)a≡a(mod d)
2)a≡b(mod d)→b≡a(mod d)
3)(a≡b(mod d),b≡c(mod d))→a≡c(mod d)
如果a≡x(mod d),b≡m(mod d),则
4)a+b≡x+m (mod d)
5)a-b≡x-m (mod d)
6)a*b≡x*m (mod d )
7)a≡b(mod d)则a-b整除d


因此,可以将大数拆分成很多个十位数或者千进制数或者万进制数这样的办法,具体哪个能过还得测试,每次获得当前的模以后,要乘以下一个数的10的位数次方,这里注意最后以为可能不到进制位数,比如你用千进制,但是最后一个数字只有两位,这时之前的模只要乘以100.


代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
#define mxl 2000100
#define mxn 110
bool is_prime[mxl];
int prime[mxl];
int cnt;
void set_prime(){
	memset(is_prime,true,sizeof(is_prime));
	for(int i=2;i<mxl;++i)	if(is_prime[i])
		for(int j=i*2;j<mxl;j+=i)
			is_prime[j]=false;
	cnt=0;
	for(int i=2;i<mxl;++i)	if(is_prime[i])
		prime[cnt++]=i;
}
char tem[mxn];
int end,a[mxn];
int l,len;
bool ok(int x){
	int cur=0;
	for(int i=0;i<end-1;++i)
		cur=(cur*1000+a[i])%x;
	int tem=a[end-1];
	while(tem){
		cur*=10;
		tem/=10;
	}
	cur=(cur+a[end-1])%x;
	if(!cur)	return true;
	return false;
}
void trans(){
	len=strlen(tem);
	end=0;
	int j;
	for(int i=0;i<len;){
		a[end]=0;
		j=i;
		while(j<len&&j-i<=2)
			a[end]=a[end]*10+(tem[j++]-'0');
		i=j;
		++end;
	}
}
int main(){
	set_prime();
	while(scanf("%s%d",tem,&l)!=EOF){
		if(!strcmp(tem,"0")&&!l)	break;
		trans();
		int ans=-1;
		for(int i=0;i<cnt;++i){
			if(prime[i]>=l)	break;
			if(ok(prime[i])){
				ans=prime[i];
				break;
			}
		}
		if(ans==-1)	puts("GOOD");
		else	printf("BAD %d\n",ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值