LGP2155题解

lg最优解来写题解啦(

题目大意:

多测:

\[\sum_{i=1}^{n!}[\gcd(i,m!)=1] \]

根据 \(\gcd\) 的结论,我们可以得到答案其实是:

\[\frac {n!} {m!} \times \varphi(m!) \]

恩,然后我们就可以直接做了

预处理 \(n!\) 及其逆元,以及 \(\varphi(n!)\)

那么怎么得到 \(\varphi(n!)\) 呢?考虑从 \(\varphi((n-1)!)\) 递推过来。

注意到 \(n!\) 有一个性质,就是其为所有不大于 \(n\) 的质数的倍数。也就是说 \(\varphi(n!)\) 可以写成:

\[\prod_p^n \varphi(p^k) \]

其中所有的 \(k\) 一定都不小于 \(1\)
分类讨论一下:

  1. \(n\) 为质数时,\(\varphi(n!)=\varphi((n-1)!) \times (n-1)\)
  2. \(n\) 不为质数时,\(\varphi(n!)=\varphi((n-1)!) \times n\)

于是可以递推得到 \(\varphi(n!)\)

那么对于前面的那个分数,都知道当 \(n \geq mod\) 并且 \(m \geq mod\) 时是不能直接算的,因为 \(n!\) 中的 \(mod\)\(m!\) 中的 \(mod\) 有可能会抵消掉。

于是在递推阶乘的时候可以特判一下,当 \(i=mod\) 时直接令 \(n!=(n-1)!\)

在计算的时候再判断一下 \(\lfloor \frac n {mod} \rfloor\) 是否等于 \(\lfloor \frac m {mod} \rfloor\) 就可以避免这个问题了。

复杂度为 \(O(n+T)\)

code:

#include<cstdio>
typedef __uint128_t L;
typedef unsigned long long ull;
const int M=1e7+5;
int T,P,mx,top,n[10005],m[10005],pri[M],phi[M],fac[M],ifac[M];bool zhi[M];
struct FastMod{
    ull b,m;
    FastMod(ull b):b(b),m(ull((L(1)<<64)/b)){}
    friend inline ull operator%(const ull&a,const FastMod&mod){
        ull q=(L(mod.m)*a)>>64;
        ull r=a-q*mod.b;
        return r>=mod.b?r-mod.b:r;
    }
}mod(2);
signed main(){
	register int i,j,x;
	scanf("%d%d",&T,&P);phi[1]=fac[1]=ifac[1]=1;mod=FastMod(ull(P));
	for(i=1;i<=T;++i)scanf("%d%d",n+i,m+i),mx=n[i]>mx?n[i]:mx,mx=m[i]>mx?m[i]:mx;
	for(i=2;i<=mx;++i){
		if(!zhi[i])pri[++top]=i,phi[i]=1;
		for(j=1;j<=top&&(x=i*pri[j])<=M;++j){
			zhi[x]=true;if(!(i%pri[j]))break;
		}
		phi[i]=i-phi[i];
	}
	for(i=2;i<=mx;++i){
		if(i^P)fac[i]=1ull*fac[i-1]*i%mod,ifac[i]=1ull*(P-P/i)*ifac[P%i]%mod;
		else fac[i]=fac[i-1],ifac[i]=1;
	}
	for(i=2;i<=mx;++i)phi[i]=1ull*phi[i-1]*phi[i]%mod,ifac[i]=1ull*ifac[i-1]*ifac[i]%mod;
	for(i=1;i<=T;++i)printf("%d\n",n[i]-n[i]%P==m[i]-m[i]%P?1ull*fac[n[i]]*ifac[m[i]]%mod*phi[m[i]]%mod:0);
}
posted @ 2022-01-10 16:55  Prean  阅读(23)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};