以下是来自AcDreamer的分析:
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2186
题意:求中与互质的数的个数,其中。
分析:因为,所以,我们很容易知道如下结论
对于两个正整数和,如果是的倍数,那么中与互素的数的个数为
本结论是很好证明的,因为中与互素的个数为,又知道,所以
结论成立。那么对于本题,答案就是
其中为小于等于的所有素数,先筛选出来即可。由于最终答案对一个质数取模,所以要用逆元,这里
求逆元就有技巧了,用刚刚介绍的递推法预处理,否则会TLE的。
结论性知识:
对于两个正整数和(n > m),如果是的倍数,那么中与互素的数的个数为
#include<iostream>
#include<cstring>
#include<cstdio>
#include <bitset>
using namespace std;
const int N = 10000005;
typedef long long ll;
bitset<N> prime;
void isprime()
{
//memset(prime, true, sizeof(prime));
prime.set();
for(int i = 2; i < N; i++)
if(prime[i])
{
for(int j = i+i; j < N; j += i)
prime[j] = false;
}
}
ll ans1[N], ans2[N];
ll inv[N];
int main()
{
isprime();
int MOD, m, n, T;
scanf("%d%d", &T, &MOD);
ans1[0] = 1;
for(int i = 1; i < N; i++)
ans1[i] = ans1[i-1] * i % MOD;
inv[1] = 1;
for(int i = 2; i < N; i++)
{
if(i >= MOD) break;
inv[i] = (MOD - MOD / i) * inv[MOD%i] % MOD;
}
ans2[1] = 1;
for(int i = 2; i < N; i++)
{
if(prime[i])
{
ans2[i] = ans2[i-1] * (i - 1) % MOD;
ans2[i] = ans2[i] * inv[i%MOD] % MOD;
}
else
ans2[i] = ans2[i-1];
}
while(T--)
{
scanf("%d%d", &n, &m);
ll ans = ans1[n] * ans2[m] % MOD;
printf("%lld\n", ans);
}
return 0;
}