bzoj 2186
非常有趣的题
题意:求1~N!中有多少个与M!互质的数,T组询问,答案对R取模
题解:
首先,因为N>M,所以N!>M!,所以答案一定有一部分是φ(M!)
接下来做一些分析:
引理:
若x与p互质,则x+kp与p互质(k∈Z)
证明:
反证法:假设x+kp与p不互质,则设gcd(x+kp,p)=d(d!=1),那么设p=k1d,x+kp=k2d,于是:
x=k2d-kk1d
所以x=(k2-kk1)d
那么gcd(x,p)=d
这与x与p互质相矛盾,假设不成立,原命题得证
那么,我们可以将N!分组,每组大小为M!(即将N!中每个数表示成kM!+c),那么每部分与M!互质的数的个数都是φ(M!),合起来就是N!/M!*φ(M!)
预处理即可,需要使用unsigned来卡常
#include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <queue> #include <stack> #define ll unsigned int #define ull unsigned long long #define maxn 10000000 using namespace std; ll n,m; ll T,R; ll inv[maxn+5]; ll mul[maxn+5]; ll pri[maxn+5]; ll phi[maxn+5]; bool used[maxn+5]; int tot=0; void init() { phi[1]=inv[0]=inv[1]=mul[0]=mul[1]=1; for(int i=2;i<=maxn;i++) { inv[i]=(ull)(R-R/i)*inv[R%i]%R; if(!used[i]) { pri[++tot]=i; } for(int j=1;j<=tot&&i*pri[j]<=maxn;j++) { used[i*pri[j]]=1; if(i%pri[j]==0) { break; } } } for(int i=2;i<=maxn;i++) { mul[i]=(ull)mul[i-1]*i%R; inv[i]=(ull)inv[i-1]*inv[i]%R; if(!used[i]) { phi[i]=(ull)phi[i-1]*(i-1)%R; }else { phi[i]=(ull)phi[i-1]*i%R; } } } int main() { scanf("%u%u",&T,&R); init(); while(T--) { scanf("%u%u",&n,&m); printf("%u\n",(ull)mul[n]*inv[m]%R*(ull)phi[m]%R); } return 0; }