Bzoj 2186: [Sdoi2008]沙拉公主的困惑 乘法逆元,线性筛,欧拉函数,数论
2186: [Sdoi2008]沙拉公主的困惑
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 2560 Solved: 857
[Submit][Status][Discuss]
Description
大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票。房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量。现在,请你帮助沙拉公主解决这个问题,由于可能张数非常大,你只需计算出对R取模后的答案即可。R是一个质数。
Input
第一行为两个整数T,R。R<=10^9+10,T<=10000,表示该组中测试数据数目,R为模后面T行,每行一对整数N,M,见题目描述 m<=n
Output
共T行,对于每一对N,M,输出1至N!中与M!素质的数的数量对R取模后的值
Sample Input
1 11
4 2
4 2
Sample Output
1
数据范围:
对于100%的数据,1 < = N , M < = 10000000
数据范围:
对于100%的数据,1 < = N , M < = 10000000
HINT
Source
题解:
因为若x和y互质,则x+y,x+2*y,x+3*y …… x+k*y 都与y互质。
所以若 x<=m! ,且x与m!互质。那么x,x+m!, x+2*m! …… x+k*m! 都与m!互质。
因为n!为m!的倍数,所以得到与m!互质的x后,则一定有n!/m! 个与m!互质的数(x的倍数)。
与m!互质且小于等于m!的数的个数就是φ(m!)。
则ans=φ(m!)*(n!/m!)%R
=m!*[∏((Pi) - 1)/(Pi)]*(n!/m!) (Pi<=m)
=m!*[∏((Pi) - 1)/(Pi)]*(n!/m!) (Pi<=m)
=[∏((Pi) - 1)/(Pi)]*n! (Pi<=m)
然后预处理出来 质数,∏((Pi) - 1)/(Pi) (Pi<=10000000) ,n!(1<=n<=10000000)。
最后O(1)输出即可。
注意:筛素数要用线性筛。QAQ
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 #define MAXN 10000000 5 #define MAXP 670010 6 int jc[MAXN+10],cj[MAXN+10],cc[MAXN+10],tot; 7 int prime[MAXP],ny[MAXP]; 8 bool vis[MAXN+10]; 9 int read() 10 { 11 int s=0,fh=1;char ch=getchar(); 12 while(ch<'0'||ch>'9'){if(ch=='-')fh=-1;ch=getchar();} 13 while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();} 14 return s*fh; 15 } 16 int ksm(LL bb,LL pp,LL kk) 17 { 18 LL s=1; 19 while(pp>0) 20 { 21 if(pp%2!=0)s=(LL)(s*bb)%kk; 22 pp/=2; 23 bb=(LL)(bb*bb)%kk; 24 } 25 return s; 26 } 27 void getprime() 28 { 29 int i,j; 30 tot=0; 31 for(i=2;i<=MAXN;i++) 32 { 33 if(vis[i]==false)prime[++tot]=i; 34 for(j=1;j<=tot&&prime[j]*i<=MAXN;j++) 35 { 36 vis[prime[j]*i]=true; 37 if(i%prime[j]==0)break; 38 } 39 } 40 /*for(i=2;i<=MAXN;i++) 41 { 42 if(vis[i]==false) 43 { 44 prime[++tot]=i; 45 for(j=i+i;j<=MAXN;j+=i)vis[j]=true; 46 } 47 }*/ 48 } 49 int main() 50 { 51 int T,R,i,N,M; 52 T=read();R=read(); 53 getprime(); 54 for(i=1;i<=tot;i++)ny[i]=ksm(prime[i],R-2,R); 55 jc[0]=1; 56 cj[0]=1; 57 for(i=1;i<=tot;i++)cc[prime[i]]=(LL)(prime[i]-1)*ny[i]%R; 58 for(i=1;i<=MAXN;i++) 59 { 60 jc[i]=(LL)jc[i-1]*i%R; 61 if(cc[i]!=0)cj[i]=(LL)cj[i-1]*cc[i]%R; 62 else cj[i]=cj[i-1]; 63 } 64 while(T--) 65 { 66 N=read();M=read(); 67 printf("%lld\n",(LL)jc[N]*cj[M]%R); 68 } 69 fclose(stdin); 70 fclose(stdout); 71 return 0; 72 }