問題描述
給定一個大數K,K是兩個大素數的乘積的值。
再給定一個int內的數L
問這兩個大素數中最小的一個是否小於L,如果小於則輸出這個素數。
解題思路
首先對題目的插圖表示無語。。。
高精度求模+同餘模定理,解題步驟:
1、 Char格式讀入K。把K轉成千進制Kt,同時變爲int型。
把數字往大進制轉換能夠加快運算效率。若用十進制則耗費很多時間,會TLE。
千進制的性質與十進制相似。
例如,把 轉成千進制,就變成了: 。
爲了方便處理,我的程序是按“局部有序,全局倒序”模式存放
即 (一箇中括號代表一個數組元素)
2、 素數打表,把10^6內的素數全部預打表,在求模時則枚舉到小於L爲止。
注意打表不能只打到100W,要保證素數表中最大的素數必須大於 ,否則當 且K爲 時,會因爲數組越界而RE,這是因爲越界後prime都是負無窮的數,枚舉的 循環會陷入死循環
3、 高精度求模。
主要利用Kt數組和同餘模定理。
例如要驗證是否被3整除,只需求模
但當123是一個大數時,就不能直接求,只能通過同餘模定理對大數“分塊”間接求模
具體做法是:
先求
再求
再求
那麼就間接得到 ,這是顯然正確的
而且不難發現,
這是在10進制下的做法,千進制也同理,改爲 就可以了,至於這裏爲什麼而不是,因爲L的大小,此時如果乘10000就不能用int型表示了。
#define ll long long
#define inf 0x3f3f3f3f
#define vec vector<int>
#define P pair<int,int>
#define MAX 1000005
string K;
int L;
bool isp[MAX];
vec v, pri;//每個v存儲着一個千位數
//檢查K是否能夠整除n
bool check(int n) {
int mod = 0;
for (int i = 0; i < v.size(); i++) {
mod = (mod * 1000 + v[i]) % n;
}
return mod == 0;
}
int main() {
fill(isp, isp + MAX, 1);
isp[0] = isp[1] = 0;
for (int i = 2; i < MAX; i++) {
if (isp[i]) {
pri.push_back(i);
for (int j = i * 2; j < MAX; j += i)
isp[j] = 0;
}
}
while (cin >> K >> L && K != "0") {
v.clear();
while (K.size() > 0) {
int t = K.size();
if (t > 3)v.push_back(atoi(K.substr(t - 3).c_str())), K.erase(t - 3, 3);
else v.push_back(atoi(K.c_str())), K.clear();
}
reverse(v.begin(), v.end());//高位在前
int id = lower_bound(pri.begin(), pri.end(), L) - pri.begin(), sign = 1, i;
for (i = 0; i < id && sign; i++) {
int n = pri[i];
if (check(n)) { sign = 0; break; }
}
if (sign)cout << "GOOD" << endl;
else cout << "BAD " << pri[i] << endl;
}
}