背景:
寫一下最近做的題目。
題目傳送門:
https://www.luogu.org/problem/P2155
題意:
求內與互質的數的個數。
思路:
這個轉化還是比較妙的。
考慮內與互質的數的個數,顯然答案爲。
考慮內與互質的數的個數。
考慮更相減損術:,因此想到,因此相當於將翻倍。
綜上。
怎麼求呢。
這個又怎麼做呢?
直接預處理即可。
設
後面的考慮我們已經求出了,那麼,由於我們可以預處理逆元,因此可以轉移。
因爲的指數必須爲,因此我們可以從小到大來做。
實測,不然對於沒有逆元的,直接做會有問題,詳細處理方法可以見題解。
代碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define R register
using namespace std;
int n,m,mod;
int prime[1000010],fac[10000010],f[10000010],inv[10000010];
bool bz[10000010];
void init(int ma)
{
int t=0;
bz[0]=bz[1]=true;
for(R int i=2;i<=ma;i++)
{
if(!bz[i]) prime[++t]=i;
for(R int j=1;j<=t&&i*prime[j]<=ma;j++)
{
bz[i*prime[j]]=true;
if(!(i%prime[j])) break;
}
}
fac[0]=1;
for(R int i=1;i<=ma;i++)
fac[i]=(LL)fac[i-1]*i%mod;
inv[0]=inv[1]=1;
for(R int i=2;i<=min(ma,mod-1);i++)
inv[i]=((LL)mod-mod/i)*inv[mod%i]%mod;
f[1]=1;
for(R int i=2;i<=ma;i++)
{
f[i]=f[i-1];
if(!bz[i]) f[i]=(LL)f[i]*inv[i]%mod*(i-1)%mod;
}
}
int main()
{
int T;
scanf("%d %d",&T,&mod);
init(10000000);
while(T--)
{
scanf("%d %d",&n,&m);
printf("%d\n",(LL)fac[n]*f[m]%mod);
}
}