The Embarrassed Cryptographerhttps://vjudge.net/problem/HDU-2303
题目大意:
给定两个数K,L 。范围:4 <= K <= 1e100 and 2 <= L <= 1e6
问K的最小质因子是否小于L,小于则输出BAD和该质因子,否则输出GOOD
特点:
1.K非常大,只能用字符存。
2.大数取余,先对前几位数取余后,*位数加上后续位数(拼回完整的数)再取余的结果和直接对大数取余相同即同余定理。
三位三位地取余能提高效率,降低复杂度。少于三位可能会TLE,而多于三位可能会超int。
但要注意的是如果字符串长度不是3的倍数,即j最后不够三位,就要特判或用变量来代替需要乘的位数。
#include<algorithm>
#include<math.h>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
#define ll long long
#define INF 0x3f3f3f3f
#define For(i,a,b) for(int i=a;i<b;i++)
#define lm(x) 1<<(x)
using namespace std;
#define N 1000003
int p[N],cnt=0,isp[N];
char k[103];
/*对2~N个数中,isp[i]==0表示i为素数,否则表示i的最小质因子,
N为素数上限,cnt是2~N中素数个数 */
void getp(){
For(i,2,N){
if(!isp[i])p[cnt++]=i;//p[i]保存2~N的素数
for(int j=0;j<cnt&&i*p[j]<N;j++){
isp[i*p[j]]=p[j];//筛除非素数:i*p[j],顺便记录i*p[j]的最小质因数
if(i%p[j]==0)break;
}
}
}
int main()
{ios::sync_with_stdio(false);
getp();
int l;
while(scanf("%s %d",k,&l)){
if(k[0]=='0'&&l==0)break;
int len=strlen(k);
int i;
for(i=0;i<cnt&&p[i]<l;i++){//枚举素数
int num=0;
for(int j=0;j<len;j+=3){//整个大数对素数取余
int b=1,tmp=0; //b的存在是防止j到最后不够三项
for(int v=j;v<j+3&&v<len;v++){//因%复杂度大,则取三位再%,减少%次数
b*=10;
tmp=tmp*10+k[v]-'0';
}
num=num*b+tmp;
num%=p[i];//k%p[i]大数取余,可先对高位取,最终到个位,不影响整个大数取余的结果
}
if(num==0)//k被素数整除,找到最小素因数或没有小于l的素因数
break;
}
if(i!=cnt&&p[i]<l)
printf("BAD %d\n",p[i]);
else
printf("GOOD\n");
}
return 0;
}
后来发现一位一位的来,也能AC。
#include<algorithm>
#include<math.h>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
#define ll long long
#define INF 0x3f3f3f3f
#define For(i,a,b) for(int i=a;i<b;i++)
#define lm(x) 1<<(x)
using namespace std;
#define N 1000003
int p[N],cnt=0,isp[N];
char k[103];
/*对2~N个数中,isp[i]==0表示i为素数,否则表示i的最小质因子,
N为素数上限,cnt是2~N中素数个数 */
void getp(){
For(i,2,N){
if(!isp[i])p[cnt++]=i;//p[i]保存2~N的素数
for(int j=0;j<cnt&&i*p[j]<N;j++){
isp[i*p[j]]=p[j];//筛除非素数:i*p[j],顺便记录i*p[j]的最小质因数
if(i%p[j]==0)break;
}
}
}
int main()
{ios::sync_with_stdio(false);
getp();
int l;
while(scanf("%s %d",k,&l)){
if(k[0]=='0'&&l==0)break;
int len=strlen(k);
int i;
for(i=0;i<cnt;i++){//枚举素数
int num=0;
for(int j=0;j<len;j++)//整个大数对素数取余
num=(num*10+k[j]-'0')%p[i];//k%p[i]大数取余(同余定理)
if(num==0||p[i]>=l)//k被素数整除,找到最小素因数或没有小于l的素因数
break;
}
if(i!=cnt&&p[i]<l)
printf("BAD %d\n",p[i]);
else
printf("GOOD\n");
}
return 0;
}