BZOJ 2186 SDOI2008 沙拉公主的困惑 数论

来源:互联网 发布:大数据薪资 编辑:程序博客网 时间:2024/05/01 12:50

题目大意:给定询问组数T和取模数P,每次询问给定两个整数n和m,求1~(n!)的数中与m!互质的数个个数模P (m<=n)

首先T<=1W,暴力肯定过不去,我们需要预处理一些东西

首先我们知道,若x与y互质,则x+y与y也互质,x+2y与y也互质。。。

换到这道题上来说,若一个数x与m!互质,那么x+(m!)也一定与m!互质,(x+m!*2)也一定与m!互质。。。

由于n!一定是m!的倍数,于是我们每存在到一个x<=m!与m!互质,我们就一定能找到(n!)/(m!)个与m!互质的数

而m!以内与m!互质的数的数量恰好是φ(m!)

于是我们要得到的数恰好就是φ(m!)*(n!)/(m!) %p

其中m!的所有质因数恰好就是m以内所有的质数 于是φ(m!)=(m!)*∏(pi-1)/pi (pi<=m)

于是最后我们的结果就是n!*∏(pi-1)/pi

质数预处理出来,n!预处理出来,pi的逆元预处理出来,∏(pi-1)/pi就可以预处理出来,都是线性的

至于pi的逆元 有一个比较快的线性求法(详见 http://blog.csdn.net/whyorwhnt/article/details/19169035 )

我的代码最后交上去超时了1.5秒AC。。。而且我还不是最慢的,wulala大神比我还要慢200+MS。。。

#include<bitset>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define M 10000001using namespace std;typedef long long ll;bool not_prime[M+100];ll prime[500500],ans[M+100],fac[M+100],rev[M+100];int n,m,p,T,tot;void Linear_Shaker(){ll i,j;for(i=2;i<=M;i++){if(!not_prime[i])prime[++tot]=i;for(j=1;j<=tot&&prime[j]*i<=M;j++){not_prime[prime[j]*i]=1;if(i%prime[j]==0)break;}}fac[1]=1;for(i=2;i<=M;i++)fac[i]=fac[i-1]*i%p;rev[1]=1;for(i=2;i<=M&&i<p;i++)rev[i]=(p-p/i)*rev[p%i]%p;ans[1]=1;for(i=2;i<=M;i++){if(!not_prime[i])ans[i]=ans[i-1]*(i-1)%p*rev[i%p]%p;elseans[i]=ans[i-1];}}int main(){scanf("%d%d",&T,&p);Linear_Shaker();for(int i=1;i<=T;++i){scanf("%d%d",&n,&m);printf("%d\n",fac[n]*ans[m]%p);}}


0 0
原创粉丝点击