愿各位程序员都能记住,输出第一条hello world时候的心情。坚持下去,你的每一条代码都在默默的改变世界,加油!加油!加油! “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。 什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。 人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。

组合数取模 【数论】

 

 

本人水平有限,题解不到为处,请多多谅解

 

本蒟蒻谢谢大家观看

 

 

题目:

3942: 组合数取模

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 113  Solved: 39
[Submit][Status][Web Board]

Description

给出N,M,P,求C(N,M) Mod P
1<=M<=N<=10^6,1<=P<=10^5,P可能为合数

Input

一行给出N,M,P

Output

如题

Sample Input

5 2 3

Sample Output

1

HINT

 

如果直接用公式暴力的话,显然会爆出long long类型,直接RE。

 

所以要优化,我们可以利用组合数公式来进一步推倒。

 

我们可以将n!写成几个质数幂的积的形式。再利用逆元不断取模即可。

我们可以先把能约的先约掉,直接指数相减即可。

 

例如:5!=1*2*3*4*5   可以写成:(2^3)*(3^1)*(5^1) 又可以写成:(2^3)%p*(3^1)%p*(5^1)%p 即可

 

我们可以先用欧拉线筛求出质数,再把质数进行求其指数,最后用快速幂还原成常数即可。

 

在上代码之前先来解释一下我的变量:

 

Isprime表示质数的顺序。例如:2为所有质数的第一个,所以Isprime[2]==1

3为所有质数的第二个,所以Isprime[3]==2  ……

 

primenum表示在n以内有多少个质数。例如:当n==10时,primenum[10]==4 因为10以内有4个质数。

 

sum表示当前质数的指数为多少。例如:2^3 为sum[2]==3

 

 

 

code:

 1 #include<bits/stdc++.h>
 2 #pragma GCC optimize(3)
 3 #define int long long
 4 const int N=1e6+10;
 5 using namespace std;
 6 int n,m,p;
 7 int Isprime[N],primenum[N],sum[N];
 8 bool vis[N];
 9 int ans=1;
10 int tot=0;
11 void inint(){
12     freopen("com.in","r",stdin);
13     freopen("com.out","w",stdout);
14 }
15 inline int read(){
16     int x=0,f=1;char ch=getchar();
17     while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
18     while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
19     return x*f;
20 }
21 inline void write(int x)
22 {
23     if(x<0)x=-x,putchar('-');
24     if(x>9)write(x/10);
25     putchar(x%10+'0');
26 }
27 int quick_mi(int a,int b){
28     if(b==0)return 1;
29     if(b%2==1)return quick_mi(a*a,b/2)*a;
30     else return quick_mi(a*a,b/2);
31 }
32 void PRIME(int x){
33     for(int i=2;i<=x;i++){
34         primenum[i]=primenum[i-1];
35         if(!vis[i]){
36             Isprime[++tot]=i;
37             primenum[i]++;
38         }
39         for(int j=1;j<=tot&&i*Isprime[j]<=x;j++){
40             vis[i*Isprime[j]]=true;
41             if(i%Isprime[j]==0)break;
42         }
43     }
44     return ;
45 }
46 void solve(int x,int y,int z,int mod){
47     for(int i=1;i<=primenum[x];i++){
48         int yzl=x;
49         while(yzl!=0){
50             sum[i]+=yzl/Isprime[i];
51             yzl=yzl/Isprime[i];
52         }
53     }
54     for(int i=1;i<=primenum[y];i++){
55         int yzl=y;
56         while(yzl!=0){
57             sum[i]-=yzl/Isprime[i];
58             yzl=yzl/Isprime[i];
59         }
60     }
61     for(int i=1;i<=primenum[z];i++){
62         int yzl=z;
63         while(yzl!=0){
64             sum[i]-=yzl/Isprime[i];
65             yzl=yzl/Isprime[i];
66         }
67     }
68     for(int i=1;i<=primenum[x];i++){
69         ans=ans*(quick_mi(Isprime[i],sum[i])%mod);
70         ans%=mod;
71     }
72     return ;
73 }
74 signed main()
75 {
76     //inint();
77     n=read(),m=read(),p=read();
78     PRIME(n);
79     solve(n,m,n-m,p);
80     printf("%lld\n",ans);
81     return 0;
82 }

 

 

 

 

 
posted @ 2019-11-06 16:37  max_lemon  阅读(283)  评论(0编辑  收藏  举报
Live2D
别人恋爱不成功,你连暗恋都不成功! 你写不出代码的原因只有一个,那就是你没有彻底理解这个算法的思想!!-----沃茨·基硕德