[Sdoi2008]沙拉公主的困惑
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
solution
有用到的性质:
1.
if gcd(x,y)==1,gcd(x+t*y,y)==1
证明:
假设x+t*y,y不互质
设p为y和x+t*y的一个公约数
那么有 (x+t*y)/p==0
x/p==0&&t*y/p==0
但是既然p是y的一个质因子,x又和y互质,所以p肯定不是x的因子,即x/p!=0
所以假设不成立
2.
φ(N)=N*(1-1/p1)*(1-1/p2)*...*(1-1/pn)
根据性质1有:
因为m<=n
从1~m!有φ(m!)个答案,那么从m!+1~2*m!还是有φ(m!)个答案,以此类推
ans=φ(m!)* n!/m!
根据性质2
φ(i)=φ(i-1)*i (i是合数)
φ(i-1)*(i-1) (i是质数)
所以只需要筛出质数,预处理出φ(m!)/m!和n!即可O(1)查询
(也可以预处理 (1-1/p1)*(1-1/p2)*...*(1-1/pn) 因为φ(m!)/m!把m!消了 )
(记得算一下内存)
某些大佬出了一组神奇数据:
1 100
3 2
mod是质数
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #define ll long long 5 using namespace std; 6 const int N=10000066; 7 8 int T,mod,n,m; 9 int prime[N/3],cnt; 10 bool he[N+10]; 11 ll phi[N+10],jie[N+10],ni[N+10]; 12 13 void chu() 14 { 15 for(int i=2;i<N;++i) 16 { 17 if(!he[i]) 18 prime[++cnt]=i; 19 for(int j=1;j<=cnt&&(ll)prime[j]*(ll)i<N;++j) 20 { 21 he[prime[j]*i]=1; 22 if(i%prime[j]==0) 23 break; 24 } 25 } 26 //prime[cnt+1]=0x7fffffff; 27 28 //cout<<cnt<<endl; 29 30 ni[1]=1; 31 for(int i=2;i<N;++i) 32 { 33 ni[i]=(ll)(mod-mod/i)*ni[mod%i]%mod; 34 } 35 36 jie[1]=1; 37 for(int i=2;i<N;++i) 38 { 39 jie[i]=jie[i-1]*ni[i]%mod; 40 //if(jie[i]==0) 41 // cout<<i<<endl; 42 } 43 44 //cout<<jie[N-100000]<<endl; 45 46 //printf("jieni[2]=%lld\n",jie[2]); 47 48 phi[1]=1; 49 phi[2]=1; 50 for(int i=3;i<N;++i) 51 { 52 if(he[i]) 53 phi[i]=phi[i-1]*(ll)i%mod; 54 else 55 phi[i]=phi[i-1]*(ll)(i-1)%mod; 56 } 57 58 for(int i=1;i<N;++i) 59 phi[i]=phi[i]*jie[i]%mod; 60 61 for(int i=2;i<N;++i) 62 jie[i]=jie[i-1]*(ll)i%mod; 63 } 64 65 int main(){ 66 67 //freopen("1.txt","r",stdin); 68 69 scanf("%d%d",&T,&mod); 70 chu(); 71 72 ll temp; 73 while(T--) 74 { 75 scanf("%d%d",&n,&m); 76 77 //printf("jie[n]=%lld\n",jie[n]); 78 //printf("phi[m]=%lld\n",phi[m]); 79 80 temp=jie[n]*phi[m]%mod; 81 printf("%lld\n",temp); 82 } 83 return 0; 84 }