题意
输入p、a,验证是否满足 a^p == a (mod p) 且 p不为素数。
说法
讲真看不懂啊!这个题是看错题号误入,看了看题目觉得还行可以做着试试,先瞄了瞄讨论没有太难的地方。
首先,题目翻译过来是“伪素数”。但是我对伪素数这个概念不是很熟悉,然而题目是有明确解释的我却没有仔细看。
再者是费马小定理的出现让人很慌。
以上的题意已经是伪素数的定义了,满足费马小定理,但是p不是素数的数,这样的p就是一个伪素数。
我最初纠结的3 2为什么是2,因为在我看来3 2 满足了费马小定理。(原因是伪素数的“伪”)。
值得一提的是,我打素数表的时候一直在wa和re,因为偷懒没有设常数,所以……
难点
p是否为素数。
讲道理,难点还是稍稍有的,如果是平时没有看过任何指点的我,应该会有冲动把1e10的素数全部打表,然而经历市赛后我发现,不如先暴力,(暴力是可以过得,直接最朴素的验证是否为素数的暴力手段是可以过得!!)。但是!这个题目,这个1e10最好的方法是先打表1e5内的素数,然后在这里面找是否有p的因子。因为1e5只需要一个2就可以到1e10,所以如果说有这么个素数可以被p整除,那么一定会在sqrt(p)的范围里,然后一定会在1e5的素数里。就很高明的有没有。
另外也就快速幂取模了(改天一定要弄懂取模的原理,我觉得我摸到边了。
#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#define mem(a,b) memset(a,b,sizeof(a))
#define sss(x,y) scanf("%x",&y)
using namespace std;
const int maxn = 100005;
const int inf = 0x3f3f3f;
typedef long long LL;
long long fpow(long long a, long long b)
{
long long ans = 1;
long long p = b,aa=a;
while (b)
{
if (b & 1)
{
ans = (ans * a) % p;
}
b /= 2;
a = (a * a) % p;
}
return ans == aa % p;
}
int pri[maxn];
int y[maxn];
int sum;
void init()
{
int cnt = 0;
for (int i = 2; i <= maxn; i++)
{
if (!y[i])pri[cnt++] = i;
for (int j = 0; i*pri[j] <= maxn && j < cnt; j++)
{
y[i*pri[j]] = 1;
if (i%pri[j]==0)break;
}
}
//for (int i = 0; i < 100; i++)
// cout << pri[i] << endl;
sum = cnt;
}
bool is_prime(long long p)//if p is a prime number return 1 else return 0
{
long long k = sqrt(p);
for (int i = 0;i < sum && pri[i]<=k; i++)
{
if (p%pri[i] == 0)return 0;
}
return 1;
}
int main()
{
//freopen("D:\\in.txt", "r", stdin);
//freopen("D:\\out.txt", "w", stdout);
init();
long long a, p;
while (cin >> p >> a && (p + a))
{
if (fpow(a, p) && !is_prime(p))
cout << "yes" << endl;
else
cout << "no" << endl;
}
//fclose(stdin);
//fclose(stdout);
system("pause");
return 0;
}