「学习笔记」 基础数论-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;
} 
posted @ 2022-07-11 20:45  StranGePants  阅读(40)  评论(0编辑  收藏  举报