洛谷P2155 [SDOI2008]沙拉公主的困惑

题面

传送门

分析

一道不是很好想的题目,还考察了欧拉函数的运用

难点在于分段,把\([m!,n!]\)拆成了若干段长度为\(m!\)的小段

然后就是一系列的推导,最后得到答案其实正是一个跟\(n!\)\(\varphi(m)\)相关的式子

最后预处理后回答询问即可

代码

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
	x=0;char ch=getchar();bool f=false;
	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template <typename T>
inline void write(T x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
const int N=1e7+5,M=1e7;
#define ll long long
int t,n,m;
ll r;
int prime[N],inv[N],ans[N],idx;
ll fac[N];
bool isprime[N];
void init(){
	isprime[1]=true;
	inv[0]=inv[1]=fac[0]=fac[1]=ans[0]=ans[1]=1;
	for(int i=2;i<=M;i++){
		fac[i]=(1ll*fac[i-1]*i)%r;
        inv[i]=1ll*(r-r/i)*inv[r%i]%r;
		if(!isprime[i]) prime[++idx]=i;
		for(int j=1;j<=idx&&prime[j]*i<=M;j++){
			isprime[prime[j]*i]=true;
			if(i%prime[j]==0) break;
		}
	}
	for(int i=2;i<=M;i++){
		ans[i]=ans[i-1];
		if(!isprime[i]) ans[i]=1ll*ans[i]*(i-1)%r*inv[i]%r;
	}
	return ;
}
int main(){
	read(t),read(r);
	init();
	while(t--){
		read(n),read(m);
		write(1ll*fac[n]*ans[m]%r),putchar('\n');
	}
	return 0;
}

posted @ 2020-12-07 21:47  __Anchor  阅读(64)  评论(0编辑  收藏  举报