LIght oj 1067 Combinations

这篇博客探讨了如何使用乘法逆元来高效地计算在给定n个不同对象中选取k个的不同方式数。通过举例说明了乘法逆元的概念,并指出在数据规模较大时直接计算不可行。博主还提到了扩展欧几里得算法作为知识点,并给出了求C(n, m) % mod的方法。文章包含3个测试用例,展示了计算结果。" 19472,3342,WinForm DataGrid 条件背景色设置,"['WinForm开发', '数据展示', '自定义控件', '数据绑定']
摘要由CSDN通过智能技术生成

Description

Given n different objects, you want to take k of them. How many ways to can do it?

For example, say there are 4 items; you want to take 2 of them. So, you can do it 6 ways.

Take 1, 2

Take 1, 3

Take 1, 4

Take 2, 3

Take 2, 4

Take 3, 4

Input

Input starts with an integer T (≤ 2000), denoting the number of test cases.

Each test case contains two integers n (1 ≤ n ≤ 106), k (0 ≤ k ≤ n).

Output

For each case, output the case number and the desired value. Since the result can be very large, you have to print the result modulo 1000003.

Sample Input

3

4 2

5 0

6 4

Sample Output

Case 1: 6

Case 2: 1

Case 3: 15

知识点:乘法逆元,扩展欧几里得。

题意:求C(n,m)%mod;

由于数据较大,不能直接求解,采用逆元;

先看逆元:

乘法逆元

定义:
满足a*k≡A (mod p)的k值就是a关于p的乘法逆元。

为什么要有乘法逆元呢?
当我们要求(a/b) mod p的值,且a很大,无法直接求得a/b的值时,我们就要用到乘法逆元。
我们可以通过求b关于p的乘法逆元k,将a乘上k再模p,即(a*k) mod p。其结果与(a/b) mod p等价。

证:
根据b*k≡1 (mod p)有b*k=p*x+1。
k=(p*x+1)/b。
把k代入(a*k) mod p,得:
(a*(p*x+1)/b) mod p
=((a*p*x)/b+a/b) mod p
=[((a*p*x)/b) mod p +(a/b)] mod p
=[(p*(a*x)/b) mod p +(a/b)] mod p        //p*[(a*x)/b] mod p=0
所以原式等于:(a/b) mod p
对于这道题,要求n%mod的逆元,直接费马小定理,n'=n^(mod-2)%mod,所以可以用快速幂求出;

代码:


<pre name="code" class="cpp">#include<string.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define mod 1000003
#define LL  long long
LL com[1000005];//存的是i的阶乘; 
LL cob[1000005];//存的是i的阶乘的mod-2次幂; 
LL pow(LL n,LL k)
{
	LL base=n,ans=1;
	while(k)
	{
		if(k%2==1)
		   ans=(ans*base)%mod;
		base=(base*base)%mod;
		k/=2;//写成k>>1,竟然超时; 
	}
	return ans;
}
void f()
{
	int i=0;
	com[0]=cob[0]=1;	
	for(i=1;i<=1000005;i++)
	{
		com[i]=(com[i-1]*i)%mod;
		cob[i]=pow(com[i],mod-2);
	}
}
int main()
{
	int t,n,k,m=1;
    f();
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&k);
		if(k>n/2)
		   k=n-k;
		LL ans=com[n]*cob[k]%mod*cob[n-k]%mod;
		printf("Case %d: %lld\n",m++,ans);
	}
	return 0;
}


 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值