POJ2635

这道题还是比较综合的数论好题

做这道题的时候卡了蛮久,主要是一个高精度的压位的问题SB了一下

题目大意:给你一个大数k和一个在int范围内的数。这个大数是两个素数的乘积,让你判断其中较小的一个素数是否小于l

首先我们看到这种素数的题目,就有点虚了不会是什么玄学乱证或者什么扩欧乱搞吧

但是仔细一想,这其实就是暴力题啊!

首先对于l的范围<=1e6,我们完全可以先筛出范围内的素数然后存起来,到时候要用的时候就直接一个一个找即可,这样只要枚举π(l)个素数了(π(x)表示的就是小于等于n的素数的个数)

然后对于一个数能否整除另一个数我们就通过同余法来做即可

例如有一个高精存储的数164,它通过同余法模7的过程如下:

  • 1%7=1,剩下1

  • 1*10+6=16,16%7=2,剩下2

  • 2*10+4=24,24%7=3,剩下3

即最终的余数为3

然后当你满怀信心的帅气提交然后发现T了

不要虚,然后我们开始压位

我们发现这样进行10进制下的模运算太慢了,我们索性给它压到1000进制

至于为什么不多压一点呢,其实这个一个时写起来不方便一点,然后也没有必要

然后我们模的时候直接把上一次的数乘上1000即可

作死开了long long然后1739MS的CODE

#include<cstdio>
 #include<cstring>
 using namespace std;
 typedef long long LL;
 const LL N=1e6+5,MAX_LEN=105,radix=3,radix_power=1000;
 char s[MAX_LEN];
 bool prime[N];
 LL l,p[N],cnt,a[MAX_LEN],tot;
 inline void get_prime(LL m)
 {
 	prime[1]=1; register LL i,j;
 	for (i=2;i<=m;++i)
 	if (!prime[i]) for (p[++cnt]=i,j=i<<1;j<=m;j+=i) prime[j]=1;
 	p[++cnt]=1e6+5;
 }
 inline void change(char *s,LL len,LL *a)
 {
 	register LL i,j; 
 	if (len%radix) tot=len/radix+1; else tot=len/radix;
 	for (j=len,i=tot;i>1;--i,j-=3)
 	a[i]=(s[j-2]-'0')*100+(s[j-1]-'0')*10+s[j]-'0';
 	if (len%radix==1) a[1]=s[1]-'0';
 	if (len%radix==2) a[1]=(s[1]-'0')*10+s[2]-'0';
 	if (len%radix==0) a[1]=(s[1]-'0')*100+(s[2]-'0')*10+s[3]-'0';
}
 inline bool check(LL m)
 {
 	LL x=0;
 	for (register LL i=1;i<=tot;++i)
 	x=(x*radix_power+a[i])%m;
 	return !x;
 }
 int main()
 {
 	register LL i; get_prime(1e6); 
 	for (;;)
 	{
 		scanf("%s%lld",s+1,&l); LL len=strlen(s+1),num;
 		if (len==1&&s[1]=='0'&&!l) break;
 		memset(a,0,sizeof(a)); change(s,len,a);
 		bool flag=1; LL now=1;
 		while (p[now]<l)
 		{
	 		if (check(p[now])) { flag=0; num=p[now]; break; }
		 	++now;
		}
 		if (flag) puts("GOOD"); else printf("BAD %lld\n",num);
 	}
 	return 0;
 }

posted @ 2018-05-25 13:41  空気力学の詩  阅读(109)  评论(0编辑  收藏  举报