比赛时花了不到一个小时的时间过了三道水题,然后看到了目前过题数第四多的B题。
题意很简单,给定任意一个在[3,2^63-1]范围内的数,将它表示成两个素数的和。
数字这么大,当然要用素数测试算法啦,比如miller-rabin。
然后花了四个小时调这题,数组都开到了2e6,结果到最后都没过。
不服气,回寝继续做。在群里看到有人说只用查到1e4就好了,而且确实是用这个算法。
那么到底是怎么回事呢?大概是因为测试用到的是一个随机数,算对的可能性可能只有3/4,然后我把测试次数从一次换成了5次就过了,顺便打了个1e5的素数表。
无话可说。还是我太菜了。
那个素数检测部分的代码是我刚才上网随便找的,忘了是谁的了,不过还是要感谢一下作者。
题目链接:
https://nanti.jisuanke.com/t/25985
放上代码回馈网友:
#include <bits/stdc++.h>
#define null NULL
#define PI acos(-1)
#define eps 1e-9
#define INF 0x7fffffff
#define debug(...) fprintf(stderr,__VA_ARGS__),fflush(stderr)
using namespace std;
typedef unsigned long long ll;
ll mod_mul(ll a, ll b, ll n) {
ll res = 0;
while(b) {
if(b&1) res = (res + a) % n;
a = (a + a) % n;
b >>= 1;
}
return res;
}
ll mod_exp(ll a, ll b, ll n) {
ll res = 1;
while(b) {
if(b&1) res = mod_mul(res, a, n);
a = mod_mul(a, a, n);
b >>= 1;
}
return res;
}
bool miller_rabin(ll n) {
if(n == 2 || n == 3 || n == 5 || n == 7 || n == 11) return true;
if(n == 1 || !(n%2) || !(n%3) || !(n%5) || !(n%7) || !(n%11)) return false;
ll x, pre, u;
int i, j, k = 0,S=5;
u = n - 1; //要求x^u % n
while(!(u&1)) { //如果u为偶数则u右移,用k记录移位数
k++; u >>= 1;
}
srand((ll)time(0));
for(i = 0; i < S; ++i) { //进行S次测试
x = rand()%(n-2) + 2; //在[2, n)中取随机数
if((x%n) == 0) continue;
x = mod_exp(x, u, n); //先计算(x^u) % n,
pre = x;
for(j = 0; j < k; ++j) { //把移位减掉的量补上,并在这地方加上二次探测
x = mod_mul(x, x, n);
if(x == 1 && pre != 1 && pre != n-1) return false; //二次探测定理,这里如果x = 1则pre 必须等于 1,或则 n-1否则可以判断不是素数
pre = x;
}
if(x != 1) return false; //费马小定理
}
return true;
}
const ll maxn=1e5;
ll arr[maxn+5];
int prime[maxn+5];
int main(){
int t=1;scanf("%d",&t);
int cnt=0;
for(ll i=0;i<=maxn;++i)
prime[i]=1;
for(ll i=2,j=maxn/2;i<=j;++i){
if(prime[i]){
arr[cnt++]=i;
for(ll j=i+i;j<=maxn;j+=i)
prime[j]=0;
}
}
while(t--){
// clock_t z=clock();
// cout<<"Case #"<<++cnt<<": ";
ll x;scanf("%llu",&x);
for(int i=0;i<cnt&&arr[i]<x;++i){
if(miller_rabin(x-arr[i])){
// cout<<arr[i]<<' '<<x-arr[i]<<endl;
printf("%llu %llu\n",arr[i],x-arr[i]);
break;
}
}
// debug("Total Time: %.8f\n", (double)(clock() - z) / CLOCKS_PER_SEC);
}
return 0;
}