1004 Fansblog (HDU - 6608)

题意:

给定一个大素数2019 Multi-University Training Contest 3 1006(Miller-Rabin素数测试+威尔逊定理+费小马定理_判断素数(2019 Multi-University Training Contest 3 1006(Miller-Rabin素数测试+威尔逊定理+费小马定理_数学_02),求最大的小于2019 Multi-University Training Contest 3 1006(Miller-Rabin素数测试+威尔逊定理+费小马定理_判断素数2019 Multi-University Training Contest 3 1006(Miller-Rabin素数测试+威尔逊定理+费小马定理_数学_04,其中2019 Multi-University Training Contest 3 1006(Miller-Rabin素数测试+威尔逊定理+费小马定理_数学_04也是素数,输出2019 Multi-University Training Contest 3 1006(Miller-Rabin素数测试+威尔逊定理+费小马定理_判断素数_06

思路:

2019 Multi-University Training Contest 3 1006(Miller-Rabin素数测试+威尔逊定理+费小马定理_判断素数_07
2019 Multi-University Training Contest 3 1006(Miller-Rabin素数测试+威尔逊定理+费小马定理_数学_08
2019 Multi-University Training Contest 3 1006(Miller-Rabin素数测试+威尔逊定理+费小马定理_n的阶乘_09

2019 Multi-University Training Contest 3 1006(Miller-Rabin素数测试+威尔逊定理+费小马定理_判断素数_10(其中n!表示n的阶乘)
威尔逊定理的逆定理也成立
2019 Multi-University Training Contest 3 1006(Miller-Rabin素数测试+威尔逊定理+费小马定理_数学_11
2019 Multi-University Training Contest 3 1006(Miller-Rabin素数测试+威尔逊定理+费小马定理_n的阶乘_12
2019 Multi-University Training Contest 3 1006(Miller-Rabin素数测试+威尔逊定理+费小马定理_数学_13
从上面我们不难看出,只需要找到这个Q答案就出来了,那么问题来了Q咋找呢?暴力吗?对就是暴力:由于每个素数之前的距离不会太大,所以可以P–然后判断素数即可,那么还有个问题就是判断素数用什么呢?群友直接暴力sqrt判断也过了我却tle这里涉及到一个Miller-Rabin素数测试:快速判断一个数是不是素数
ps:p–遍历的时候开始用ans记录分母,因为涉及到除法取摸,所以用到乘法逆元,费马小定理:2019 Multi-University Training Contest 3 1006(Miller-Rabin素数测试+威尔逊定理+费小马定理_数学_14
2019 Multi-University Training Contest 3 1006(Miller-Rabin素数测试+威尔逊定理+费小马定理_乘法逆元_15(这里a和p互质)

代码:

#include<bits/stdc++.h>
using namespace std;
#define
#define
#define
#include <iostream>

ll q_mul(ll a, ll b, ll mod) {
ll ans = 0;
a %= mod;
while (b) {
if (b & 1)
ans = (ans + a) % mod;
a = (a + a) % mod;
b >>= 1;
}
return ans % mod;
}

ll pow_mod(ll a, ll b, ll n) {
ll ans = 1,t = a % n;
while (b) {
if (b & 1)
ans = q_mul(ans, t, n) % n;
t = q_mul(t, t, n) % n;
b = b >> 1;
}
return ans;
}

bool isprime(ll n) {
ll pan[10] = {2, 3, 5, 7, 11, 31, 61, 73, 233, 331};
ll i;
for (i = 0; i < 10; i++)
if (pow_mod(pan[i], n - 1, n) != 1)
break;//if(pan[i]^(n-1)%n==1)this int is prime
if (i == 10)
return true;
else
return false;
}

int main() {
ll ans, p;
int t;
while (~scanf("%d", &t)) {
while (t--) {
scanf("%lld", &p);
ans = 1;
for (ll i = p - 1; i > 0; i--) {
if (isprime(i)) {
break;
} else {
ans = q_mul(ans, i, p);
}
}
ans = pow_mod(ans, p - 2, p);
ans = q_mul(p-1,ans,p);
printf("%lld\n", ans);
}
}
return 0;
}