【BZOJ2186】沙拉公主的困惑(数论)

【BZOJ2186】沙拉公主的困惑(数论)

题面

BZOJ

题解

考虑答案是啥
先假设\(n=m\)
现在求的就是\(\varphi(m!)\)
但是现在\(n!\)\(m!\)的若干倍
我们知道
\(gcd(x,y)=gcd(x+ky,y)\)
所以,相当于
每隔\(m!\),答案增长的值都是\(\varphi(m!)\)
所以
我们可以得出

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

后面的\(\varphi\)可以直接拆开,枚举质因数

\[ans=\frac{n!}{m!}·m!\frac{\prod (p_i-1)}{\prod p_i} \]

\[ans=n!\frac{\prod (p_i-1)}{\prod p_i} \]

其中,\(pi<=m\)
所以,预处理\(n!\),质数的前缀乘,还有质数\(-1\)的前缀乘
至于逆元就不要预处理了(慢的死)
要用的时候直接快速幂算一下

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define MAX 10000000
inline int read()
{
	int x=0,t=1;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=-1,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return x*t;
}
int R;
int n,m;
bool zs[MAX+1];
int pri[MAX/10],tot,jc[MAX+1];
int inv[MAX+1],pinv[MAX/10],ppri[MAX/10];
int Pos[MAX+1];
int fpow(int a,int b)
{
	int s=1;
	while(b){if(b&1)s=1ll*s*a%R;a=1ll*a*a%R;b>>=1;}
	return s;
}
void pre()
{
	zs[1]=true;inv[1]=jc[1]=1;
	for(int i=2;i<=MAX;++i)
	{
		jc[i]=1ll*jc[i-1]*i%R;
		if(!zs[i])pri[++tot]=i;//,inv[i]=fpow(i,R-2);
		for(int j=1;j<=tot&&i*pri[j]<=MAX;++j)
		{
			zs[i*pri[j]]=true;
			//inv[i*pri[j]]=1ll*inv[i]*inv[pri[j]]%R;
			if(i%pri[j]==0)break;
		}
	}
	pinv[0]=ppri[0]=1;
	for(int i=1;i<=tot;++i)pinv[i]=1ll*pinv[i-1]*pri[i]%R;
	for(int i=1;i<=tot;++i)ppri[i]=1ll*ppri[i-1]*(pri[i]-1)%R;
	for(int i=1;i<=tot;++i)
		for(int j=pri[i];j<pri[i+1];++j)
			Pos[j]=i;
}
int Query(int n,int m)
{
	return 1ll*jc[n]*fpow(pinv[Pos[m]],R-2)%R*ppri[Pos[m]]%R;
}
int main()
{
	int T=read();R=read();
	pre();
	while(T--)
	{
		n=read();m=read();
		printf("%d\n",Query(n,m));
	}
	return 0;
}

posted @ 2018-01-20 11:55  小蒟蒻yyb  阅读(322)  评论(3编辑  收藏  举报