求C(n,m)对k取模后的值,已知公式如下
shuoj1937-组合数level 0
Description
求C(n,m)对1000000007取模后的值,已知公式如下
Input
第一行有一个整数T,表示有T组数据(T≤1000)
接下来有T行,每行有两个整数n,m,用空格隔开。
0≤n≤20,0≤m≤n
Output
对于每组数据,输出答案并换行
Sample Input
2
4 2
5 2
Sample Output
6
10
题解::通过看题本题的n,m<=20,可以应用组合数的知识直接求解。但有点要注意mod不满足除法,不能在求阶乘时mod。
代码::
#include <iostream> #include <sstream> #include <ios> #include <iomanip> #include <functional> #include <algorithm> #include <vector> #include <string> #include <list> #include <queue> #include <deque> #include <stack> #include <set> #include <map> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <climits> #include <cctype> using namespace std; #define XINF INT_MAX #define INF 0x3FFFFFFF #define MP(X,Y) make_pair(X,Y) #define PB(X) push_back(X) #define REP(X,N) for(int X=0;X<N;X++) #define REP2(X,L,R) for(int X=L;X<=R;X++) #define DEP(X,R,L) for(int X=R;X>=L;X--) #define CLR(A,X) memset(A,X,sizeof(A)) #define IT iterator typedef long long ll; typedef pair<int,int> PII; typedef vector<PII> VII; typedef vector<int> VI; const int MOD = 1e9+7; ll factorial(ll a) { ll fac = 1,cnt = a; for(int i = 1;i<cnt;i++){ fac = fac*a; a -=1; } return fac; } int main(){ int T; cin>>T; while(T--) { ll a,b; cin>>a>>b; ll fa,fb,fc; fa = factorial(a); fb = factorial(b); fc = factorial(a - b); cout<<(fa/fb/fc)%MOD<<endl; } return 0; }
shuoj1938-组合数level 1
Description
求C(n,m)对1000000007取模后的值,已知公式如下
Input
第一行有一个整数T,表示有T组数据(T≤10^5)
接下来有T行,每行有两个整数n,m,用空格隔开。0≤n≤1000,0≤m≤n
Output
对于每组数据,输出答案并换行
Sample Input
2
4 2
5 2
Sample Output
6
10
HINT
输入和输出的数据规模较大,请使用scanf和printf
Source
xyiyy
题解:: 这道题很明显的不同之处(1)数据量变大了(2)n,m的值变大了。这时候取模的作用真正的用上了。我们的问题转化成组合数取模而不是单单的求组合数,应用上面的方法求解不再满足要求(会超时)。
但我们在初中都学过C(i,j) = C(i-1,j) + C(i-1,j-1).很自然的我们想到用dp的思想或者记忆化搜索的方法将0<=n,m<=1000的所有值存到数组中,每次询问直接调用。
dp代码::
#include <iostream> #include <sstream> #include <ios> #include <iomanip> #include <functional> #include <algorithm> #include <vector> #include <string> #include <list> #include <queue> #include <deque> #include <stack> #include <set> #include <map> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <climits> #include <cctype> using namespace std; #define XINF INT_MAX #define INF 0x3FFFFFFF #define MP(X,Y) make_pair(X,Y) #define PB(X) push_back(X) #define REP(X,N) for(int X=0;X<N;X++) #define REP2(X,L,R) for(int X=L;X<=R;X++) #define DEP(X,R,L) for(int X=R;X>=L;X--) #define CLR(A,X) memset(A,X,sizeof(A)) #define IT iterator typedef long long ll; typedef pair<int,int> PII; typedef vector<PII> VII; typedef vector<int> VI; const ll MOD = 1000000007; ll dp[1005][1005]; void com_num(int t,int mod)//生成1000以内的所有组合数 { REP2(i,0,t) { REP2(j,0,i) { if(j == 0||j==i)dp[i][j] = 1; else dp[i][j] = (dp[i-1][j]%mod+dp[i-1][j-1]%mod)%mod; } } } int main() { com_num(1000,MOD); int T; scanf("%d",&T); while(T--) { int a,b; scanf("%d%d",&a,&b); printf("%lld\n",dp[a][b]); } return 0; }
#include <sstream> #include <ios> #include <iomanip> #include <functional> #include <algorithm> #include <vector> #include <string> #include <list> #include <queue> #include <deque> #include <stack> #include <set> #include <map> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <climits> #include <cctype> using namespace std; #define XINF INT_MAX #define INF 0x3FFFFFFF #define MP(X,Y) make_pair(X,Y) #define PB(X) push_back(X) #define REP(X,N) for(int X=0;X<N;X++) #define REP2(X,L,R) for(int X=L;X<=R;X++) #define DEP(X,R,L) for(int X=R;X>=L;X--) #define CLR(A,X) memset(A,X,sizeof(A)) #define IT iterator typedef long long ll; typedef pair<int,int> PII; typedef vector<PII> VII; typedef vector<int> VI; const ll MOD = 1000000007; ll dp[1005][1005]; //计算C(m,n)对mod取模,每求一次就要调用一次;A,B是记忆化搜索的关键 ll com_num(int m,int n,int mod){ if(dp[m][n]) return dp[m][n];//已经搜索过的避免重复 if(m == n||n == 0)return 1;//终止条件 dp[m][n] = (com_num(m-1,n-1,mod)+com_num(m-1,n,mod))%mod; return dp[m][n]; } int main() { int T; scanf("%d",&T); while(T--) { int a,b; scanf("%d%d",&a,&b); printf("%lld\n",com_num(a,b,MOD));//直接输出com_num()的返回值即可 } return 0; }
求C(n,m)对k取模后的值,已知公式如下
第一行有一个整数T,表示有T组数据(T≤10)
接下来有T行,每行有三个整数n,m,k,用空格隔开。
0≤n≤10^5,0≤m≤n,1≤k≤10^9+7
对于每组数据,输出答案并换行
xyiyy
题解::可以发现m,n从1000涨到100000。我们可以想到的一种方法通过把n,m,(n-m)分解素因子将因子存放在数组中,让n中的减掉m,(n-m)中的然后乘起来对mod取模。这是一种解题的好思路,但是会遇到两个问题::(1)分解素因子(2)把多个因子乘起来(如果说有1e5个2,1e5个3……就很有可能超时)所以我们还需要一个求快速幂的方法。这两个问题解决了就ok了。
(1)我们可以通过枚举[2 , 根号n]的方式求出n的素因子分解
(2)我们发现看k^13 = k^8*k^4*k^1用二进制表示k^(1101) = k^(1000)*k^(100)*k^(1),求快速幂的诀窍就在这里。思路代码里见或者点下面的链接:快速幂
代码::
#include <iostream> #include <sstream> #include <ios> #include <iomanip> #include <functional> #include <algorithm> #include <vector> #include <string> #include <list> #include <queue> #include <deque> #include <stack> #include <set> #include <map> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <climits> #include <cctype> using namespace std; #define XINF INT_MAX #define INF 0x3FFFFFFF #define MP(X,Y) make_pair(X,Y) #define PB(X) push_back(X) #define REP(X,N) for(int X=0;X<N;X++) #define REP2(X,L,R) for(int X=L;X<=R;X++) #define DEP(X,R,L) for(int X=R;X>=L;X--) #define CLR(A,X) memset(A,X,sizeof(A)) #define IT iterator typedef long long ll; typedef pair<int,int> PII; typedef vector<PII> VII; typedef vector<int> VI; //const int MAXN = 10010; //#define INF 0x3FFFFFFF //const int MOD = 1e9+7; int a[100005];//此处数组不能小于100000 int b[100005]; int c[100005]; void fenjie1(int x){//分解竭诚 int k; for(k = x;k>1;k--){ int j = k;int i; for(i = 2;i*i<=j;i++){ while(j%i==0){ a[i]++; j /=i; } } if(j!=1) a[j]++; } } void fenjie2(int x){ int k; for(k = x;k>1;k--){ int j = k;int i; for(i = 2;i*i<=j;i++){ while(j%i==0){ b[i]++; j /=i; } } if(j!=1) b[j]++; } } void fenjie3(int x){ int k; for(k = x;k>1;k--){ int j = k;int i; for(i = 2;i*i<=j;i++){ while(j%i==0){ c[i]++; j /=i; } } if(j!=1) c[j]++; } } ll fast_mod(int n,int m,int k){ ll ans = 1; while(m){ if(m&1)ans = ans * n % k; m>>=1; n = n*n%k; } return ans; } int main(){ int T ; int m,n,k; ll answer; cin>>T; while(T--){ cin>>m>>n>>k; answer = 1; memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(c,0,sizeof(c)); fenjie1(m); fenjie2(n); fenjie3(m-n); REP(i,100005){ a[i] = a[i] - b[i] - c[i]; if(a[i]!= 0) answer = answer * fast_mod(i,a[i],k)%k; } cout<<answer<<endl; } return 0; }
求C(n,m)对k取模后的值,已知公式如下
第一行有一个整数T,表示有T组数据(T≤100)
接下来有T行,每行有三个整数n,m,k,用空格隔开。
0≤n≤10^5,0≤m≤n,1≤k≤10^9+7,并且保证k为素数
对于每组数据,输出答案并换行
xyiyy
题解::由题知,组数T从10 变成100,这样会造成TLE,同时k也有了变化,从任意数变成素数。这是就要转换思路求解,我们知道通过费马小定理知道:
a*x =1 mod k
>>
x = a ^ -1 mod k
>>
(当k为素数时,a^k mod k = a mod k:费马小定理)
>>
a^(k-1) modk = 1 mod k
>>
x = a^-1 mod k = a^(k-2) mod k (a的逆元)
所以设inv(a,k)为求a在mod为k时的逆元
C(n,m) = fac[n]/(fan[m]*fan[n-m] mod k) = fac[n] * inv (fan[m]*fan[n-m] mod k, k) mod k;
当且仅当gcd(a,k) == 1时逆元存在
#include <iostream> #include <sstream> #include <ios> #include <iomanip> #include <functional> #include <algorithm> #include <vector> #include <string> #include <list> #include <queue> #include <deque> #include <stack> #include <set> #include <map> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <climits> #include <cctype> using namespace std; #define XINF INT_MAX #define INF 0x3FFFFFFF #define MP(X,Y) make_pair(X,Y) #define PB(X) push_back(X) #define REP(X,N) for(int X=0;X<N;X++) #define REP2(X,L,R) for(int X=L;X<=R;X++) #define DEP(X,R,L) for(int X=R;X>=L;X--) #define CLR(A,X) memset(A,X,sizeof(A)) #define IT iterator typedef long long ll; typedef pair<int,int> PII; typedef vector<PII> VII; typedef vector<int> VI; ll fac[100005]; void qfac(int n,int k){ fac[1] = 1; REP2(i,2,n) fac[i] = fac[i-1]*i%k; } ll fast_mod(ll n,int m,int k){ ll ans = 1; while(m){ if(m&1) ans = ans*n%k; m>>=1; n = n*n%k; } return ans; } ll inv(ll n,int k){ ll ans = fast_mod(n,k-2,k); return ans; } int main(){ int m,n,k; int T; cin>>T; while(T--){ cin>>m>>n>>k; memset(fac,0,sizeof(fac)); qfac(m,k); //REP(i,10)cout<<fac[i]<<endl; cout<<fac[m]*inv(fac[n],k)%k*inv(fac[m-n],k)%k<<endl; } return 0; }