「学习笔记」 基础数论-Summar Vacation Trainning Day4
沙拉公主的困惑
不难发现与 m! 互质的数在 [m+1,n!] 中产生,这些数实则可以表示为 p*m!+q(\(0\leq q\leq m-1\))。
q 与 m 互质,那么答案就是 \(\frac{n!}{m!}\phi(m!)\) 了。
对于前一部分,因为阶乘在中途可能会变为0,所以直接用 zkw 线段树维护区间乘积。
至于后一部分,根据欧拉函数的求法,枚举i=1~m,若 i 为质数,产生贡献就是 i-1,否则肯定分解成之前的质数乘积,贡献直接就是 i 了。
也就是可以线性求阶乘的欧拉函数。
挺有趣哈(虽然听了 lihan 聚聚的提示)。
Code:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define ll long long
const int MAXN=1e7;
const int MAXP=1e7;
int cnt,p;
int T,r,n,m,pp[MAXP+5],phi[MAXN+5],dsy[(MAXN<<2)+5];
bool vis[MAXN+5];
void Ola(){
vis[0]=vis[1]=1;
phi[1]=1;
for(int i=2;i<=MAXN;i++){
if(!vis[i]){
pp[++cnt]=i;
}
for(int j=1;j<=cnt&&pp[j]<=MAXN/i;j++){
vis[i*pp[j]]=1;
if(i%pp[j]==0){
break;
}
}
}
}
void bui(){
p=1;
while(p<MAXN+2) p<<=1;
for(int i=1;i<=MAXN;i++){
dsy[i+p]=i;
}
for(int i=p+MAXN+1;i>1;i--){
dsy[i>>1]=((ll)dsy[i>>1]*dsy[i])%r;
}
}
ll Sum(int l,int rr){
l=l+p-1,rr=rr+p+1;ll res=1;
for(;(l^rr)!=1;l>>=1,rr>>=1){
if(!(l&1)) res=(res*(ll)dsy[l^1])%r;
if(rr&1) res=(res*(ll)dsy[rr^1])%r;
}
return res;
}
int main(){
scanf("%d%d",&T,&r);
for(int i=0;i<(MAXN<<2)+5;i++) dsy[i]=1;
Ola();
for(int i=2;i<=MAXN;i++){
if(!vis[i]) phi[i]=(ll)phi[i-1]*(i-1)%r;
else phi[i]=(ll)phi[i-1]*i%r;
}
bui();
while(T--){
scanf("%d%d",&n,&m);
ll tmp=Sum(m+1,n),res=(ll)phi[m];
printf("%lld\n",res*tmp%r);
}
return 0;
}
本文来自博客园,作者:{StranGePants},转载请注明原文链接:https://www.cnblogs.com/StranGePants/p/16467828.html