正题
题目链接:
https://www.lydsy.com/JudgeOnline/problem.php?id=2186
https://www.luogu.org/problem/P2155
题目大意
求∑i=1n!((i,m!)==1)\sum_{i=1}^{n!}((i,m!)==1)i=1∑n!((i,m!)==1)
解题思路
因为gcd(m!,i)=1⇒gcd(m!,i+m!)=1gcd(m!,i)=1\Rightarrow gcd(m!,i+m!)=1gcd(m!,i)=1⇒gcd(m!,i+m!)=1所以这个互质的个数是一循环节。而又因为n≥mn\geq mn≥m所以答案就是
n!m!φ(m!)\frac{n!}{m!}\varphi(m!)m!n!φ(m!)
而因为m!m!m!质因数分解后是包括1∼m1\sim m1∼m里的所有素数所以有
⇒n!m!m!∏i=1kpi−1pi\Rightarrow\frac{n!}{m!}m!\prod_{i=1}^k\frac{p_i-1}{p_i}⇒m!n!m!i=1∏kpipi−1
n!∏i=1kpi−1pin!\prod_{i=1}^k\frac{p_i-1}{p_i}n!i=1∏kpipi−1
线性筛素数+线性推逆元预处理即可
时间复杂度O(m+T)O(m+T)O(m+T)
codecodecode
#pragma GCC optimize(2)
%:pragma GCC optimize(3)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=10000000;
int n,m,cnt,prime[N+10],inv[N+10];
int Phi[N+10],Phinv[N+10],Fac[N+10],pos[N+10],p,T;
bool v[N+10];
int main()
{v[1]=1;scanf("%d%d",&T,&p);for(int i=2;i<=N;i++){pos[i]=pos[i-1];if(!v[i]) prime[++cnt]=i,pos[i]++;for(int j=1;j<=cnt&&i*prime[j]<=N;j++){v[prime[j]*i]=1;if(!(i%prime[j])) break;}}inv[1]=Phi[0]=Phinv[0]=Fac[1]=1;for(int i=2;i<=N;i++){inv[i]=(long long)(p-p/i)*inv[p%i]%p;Fac[i]=(long long)Fac[i-1]*i%p;}for(int i=1;i<=cnt;i++){Phi[i]=(long long)Phi[i-1]*(prime[i]-1)%p;Phinv[i]=(long long)Phinv[i-1]*inv[prime[i]]%p;}while(T--){scanf("%d%d",&n,&m);printf("%d\n",(long long)Fac[n]*Phi[pos[m]]%p*Phinv[pos[m]]%p);}
}