这道题还是比较综合的数论好题
做这道题的时候卡了蛮久,主要是一个高精度的压位的问题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
",num);
}
return 0;
}