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;
}
Description
求C(n,m)对k取模后的值,已知公式如下
Input
第一行有一个整数T,表示有T组数据(T≤10)
接下来有T行,每行有三个整数n,m,k,用空格隔开。
0≤n≤10^5,0≤m≤n,1≤k≤10^9+7
Output
对于每组数据,输出答案并换行
Sample Input
Sample Output
Source
题解::可以发现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;
}
1940: 组合数level3
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 26 Solved: 13
[ Submit][ Status][ Web Board]
Description
求C(n,m)对k取模后的值,已知公式如下
Input
第一行有一个整数T,表示有T组数据(T≤100)
接下来有T行,每行有三个整数n,m,k,用空格隔开。
0≤n≤10^5,0≤m≤n,1≤k≤10^9+7,并且保证k为素数
Output
对于每组数据,输出答案并换行
Sample Input
Sample Output
Source
题解::由题知,组数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;
}