当前位置: 代码迷 >> 综合 >> POJ 2635 The Embarrassed Cryptographer尴尬的译解密码者
  详细解决方案

POJ 2635 The Embarrassed Cryptographer尴尬的译解密码者

热度:65   发布时间:2023-12-19 16:03:46.0

2015年5月17日

题目大意,给你一个数K(4 <= K <= 10^100)和一个 L(2<=L<=10^6),K是由两个因子组成,若K最小的因子大于等于L,输出 GOOD,否则输出BAD和这个小于L的因子。多组输入,最多20组。

K这个数很大,不能用基本的数据类型处理,应用高精度来做,用一个字符数组来模拟。很容易想到的一个做法是,用高精度模拟出这个数,然后枚举K的因子x(2- L),若K除这个数x等于0,则就找到一个K的因子x,并且这个因子是小于L的,所以输出BAD x。若没有找到一个x能被K整除,则输出GOOD。分析一下时间复杂 度,对于每个K需要枚举的数是2-L这个范围,这里就是100*10^6,还有20组测试数据,所以总的时间复杂度是O(20*100*10^6),题目限制是3000MS,很明 显这里是过不了的。这里有一个优化方法,就是用埃氏素筛法将2-10^6的素数筛 选出来放在prim[]数组里,对于每个K,只需枚举2-L之间的素数就可以了,这 样你还是不能AC。还可以做一个优化,用一个10^12进制的数来模拟这个K。

所以,解决此题的方法:高精度模拟,用埃氏素筛将2-10^5的数筛选出来,用10^12进制模拟。

贴出代码,供大家参考。

#include <cstdio>
#include <cstring>
#define maxn 1000007
#define MAXN 101
#define LL long long 
LL prim[maxn];
LL arr[MAXN];
bool is_prim[maxn];
int Init()
{for(int i = 2; i * i < maxn; ++i){if(!is_prim[i])for(int j = 2 * i; j < maxn; j += i)is_prim[j] = true;}int pos = 0;for(LL i = 2; i < maxn; ++i)if(!is_prim[i]) prim[pos++] = i;return pos;
}
int main()
{int N = Init();char ch[MAXN];int L;while(scanf("%s%d", ch, &L), ch[0] != '0', L){int len = strlen(ch), pos = 0, num = 12, p = len % num;LL val = 1;while(p--) val *= 10;for(int i = 0; i < len; i += num){LL val = 0;for(int j = i; j < i + num && j < len; ++j)val = val * 10 + ch[j] - '0';arr[pos++] = val;}bool flag = true;for(int i = 0; prim[i] < L && i < N; ++i){LL Mod = 0;for(int j = 0; j < pos; ++j){if(j != pos - 1) Mod = (Mod * 1000000000000 + arr[j]) % prim[i];else Mod = (Mod * val + arr[j]) % prim[i];}if(Mod == 0){printf("BAD %d\n", prim[i]);flag = false;break;}}if(flag) puts("GOOD");}return 0;
}