http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3980
这道题是CCPC2017秦皇岛热身赛的一道原题,当时认为可以大表出来,结果没打成。后来比赛结束后想到可以用Miller-Rabin算法来处理素数。
MR测试其实就是利用了费马小定理
ap−1≡1(modp)
a
p
−
1
≡
1
(
m
o
d
p
)
,a,p互质,p是质数,那么我们随便找个底数a判断一下就行,然而这个定理是充分不必要的,有可能出现伪素数或者Carmichael数,那么我们还需要一个定理:如果p是素数,x是小于p的正整数,且
x2modp=1
x
2
m
o
d
p
=
1
,那么要么x=1,要么x=p-1
以上证明请参照http://www.matrix67.com/blog/archives/234
这道题首先构造出两个数字组成的多位数,像是22223333这样的,然后让next_permutation() do their job ,得出所有的数拿MR测试一check就行,然而乘法会爆long long要注意,不要用加法代替取模,会超时。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <set>
#include <cmath>
#include <ctime>
#define rd(x) (rand()%(x))
using namespace std;
typedef unsigned long long ll;
ll mod_mul(ll x, ll y, ll mod) // 乘法防止溢出, 如果p * p不爆ll的话可以直接乘; O(1)乘法或者转化成二进制加法
{
return (x * y - (ll)(x / (long double)mod * y + 1e-3) * mod + mod) % mod;
}
long long pow_mod(long long a, long long b, long long n) {
long long res = 1;
while(b) {
if(b & 1)
res = mod_mul(res, a, n);
a = mod_mul(a, a, n);
b >>= 1;
}
return res;
}
bool test(ll n,ll a,ll d)
{
if(n==2) return true;
if(n==a) return false;
if(!(n&1)) return false;
while(!(d&1)) d>>=1;
ll t = pow_mod(a,d,n);
while(d!=n-1&&t!=n-1&&t!=1){
t = mod_mul(t,t,n);//下面介绍防止溢出的办法,对应数据量为10^18次方;
d<<=1;
}
return t == n-1||(d&1)==1;//要么t能变成n-1,要么一开始t就等于1
}
bool isprime(ll n)
{
int a[] = {2,3,5,233,331};//或者自己生成[2,N-1]以内的随机数rand()%(n-2)+2
for(int i = 0; i < 5; ++i){
if(n==a[i]) return true;
if(!test(n,a[i],n-1)) return false;
}
return true;
}
vector<ll> res;
set<ll> ans;
void dfs(int *a,int len)
{
do
{
ll temp = 0;
if(a[0] == 0)
continue;
for(int i = 0; i<len; i++)
{
temp = temp*10 + a[i];
}
res.push_back(temp);
}
while(next_permutation(a,a+len));
}
int a[20];
int main()
{
for(int i = 0; i<=9; i++)
{
for(int j = i+1; j<=9; j++)
{
for(int k = 1; k<=8; k++)
{
for(int l = 0; l<k; l++)
{
a[l] = i;
a[l+k] = j;
}
dfs(a,k*2);
}
}
}
for(int i =0;i<(int)res.size();i++)
{
//cout<<res[i]<<endl;
if(isprime(res[i]))
ans.insert(res[i]);
}
//cout<<ans.size()<<endl;
for(set<ll>::iterator it = ans.begin();it != ans.end() ;it++)
{
printf("%lld\n",(*it));
}
return 0;
}