HDU 1905 Pseudoprime numbers (快速幂+判断素数技巧)

题意

输入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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值