题意:判断一个数n(2 < n < 6500)是否是一个Carmichael数,
成立条件:1、是合数;
2、对于任意一个2<= a <= n-1,都是有a^n mod n = a。
——>>刚学了个矩阵快速幂,想起还有个快速幂取模,找到这题,核心思想与矩阵快速幂是一样的,另外加上个合数的判断,判断方法可先打素数表,二分查找。
另外有个重大发现,那个mod的n是不变的(就是输入的n),而那个指数n是变化的。
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 65000 + 10;
int p[maxn], cnt;
bool vis[maxn];
void prime_table() //筛素数
{
memset(vis, 0, sizeof(vis));
for(int i = 2; i < maxn; i++) if(!vis[i])
for(int j = (i<<1); j < maxn; j += i) vis[j] = 1;
cnt = 0;
for(int i = 2; i < maxn; i++)
if(!vis[i]) p[cnt++] = i;
}
bool bs(int* A, int x, int y, int v) //二分查找
{
int m;
while(x < y)
{
m = x + (y-x) / 2;
if(A[m] == v) return 1;
else if(A[m] > v) y = m;
else x = m+1;
}
return 0;
}
int pow_mod(int a, int n, int m) //二分幂取模
{
if(n == 1) return a % m;
long long x = pow_mod(a, n/2, m);
long long ans = x * x % m;
if(n&1) ans = ans * a % m;
return ans;
}
int main()
{
int n;
prime_table();
while(~scanf("%d", &n))
{
if(!n) return 0;
bool ok = 0;
if(!bs(p, 0, cnt, n))
{
ok = 1;
for(int i = 2; i <= n-1; i++)
if(pow_mod(i, n, n) != i)
{
ok = 0;
break;
}
}
if(ok) printf("The number %d is a Carmichael number.\n", n);
else printf("%d is normal.\n", n);
}
return 0;
}