【BZOJ2186】【SDOI2008】沙拉公主的困惑
啥都不会只能学数论QAQ
原题:
大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票。房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量。现在,请你帮助沙拉公主解决这个问题,由于可能张数非常大,你只需计算出对R取模后的答案即可。R是一个质数。
1<=M<=N<=10000000
恩,欧拉函数推推推,无果,gg看题解
首先如果gcd(x,y)=1,那么gcd(x+y,y)=1,gcd(x+2y,y)=1
那么如果x跟m!互质,x+m!与m互质,x+2*m!也与m互质
因为m<=n所以n一定是m的倍数,所以对于每个x<=m!且与m!互质,都存在(n!)/(m!)个x也与m!互质
那么答案就是phi(m)*(n!)/(m!)
因为m!的质因子刚好是<=m的所有质数,所以根据欧拉函数的通式,phi(m!)=(m!)*π((pi-1)/pi) (pi<=m)
把phi代进去答案就变成了(n!)*π((pi-1)/pi) (pi<=m)
因为n,m都<=1e7所以把质数,n!,pi的逆元预处理出来就可以把π((pi-1)/pi)页预处理出来
对于每次询问直接计算即可
线筛逆元似乎挺有用的
什么都不会数论只能看题解怎么办啊QAQ
代码:
1 #include<bitset> 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #define M 10000001 7 using namespace std; 8 typedef long long ll; 9 bool not_prime[M+100]; 10 ll prime[500500],ans[M+100],fac[M+100],rev[M+100]; 11 int n,m,p,T,tot; 12 void Linear_Shaker() 13 { 14 ll i,j; 15 for(i=2;i<=M;i++) 16 { 17 if(!not_prime[i]) 18 prime[++tot]=i; 19 for(j=1;j<=tot&&prime[j]*i<=M;j++) 20 { 21 not_prime[prime[j]*i]=1; 22 if(i%prime[j]==0) 23 break; 24 } 25 } 26 fac[1]=1; 27 for(i=2;i<=M;i++) 28 fac[i]=fac[i-1]*i%p; 29 rev[1]=1; 30 for(i=2;i<=M&&i<p;i++) 31 rev[i]=(p-p/i)*rev[p%i]%p; 32 ans[1]=1; 33 for(i=2;i<=M;i++) 34 { 35 if(!not_prime[i]) 36 ans[i]=ans[i-1]*(i-1)%p*rev[i%p]%p; 37 else 38 ans[i]=ans[i-1]; 39 } 40 } 41 int main() 42 {freopen("ddd.in","r",stdin); 43 scanf("%d%d",&T,&p); 44 Linear_Shaker(); 45 for(int i=1;i<=T;++i) 46 { 47 scanf("%d%d",&n,&m); 48 printf("%d\n",fac[n]*ans[m]%p); 49 } 50 }