吉首大学新星杯-A

比赛的时候这题卡了我很久,我看过了一些类似唯一分解定理的东西,但着实用的不娴熟,最后只贡献了几发wa

首先有一个数论的定理:唯一分解定理

整数的唯一分解定理:一个大于1的整数一定可以被分解成若干质数的乘积,

X=e1^k1 * e2^k2 * …… * en^kn=mul{ei*ki | 1<= i <= n},X >= 2,e是质数。

任何数都可以表示成若干质数乘积的形式,因此就有了推论:

n的因数定理:设正整数n的所有素因子分解n=p1^a1 * p2^a2 *p3^a3 **** Ps^as,那么

T(n)=(a1+1)*(a2+1)*(a3+1)***(an+1);(求因子的个数的公式)

可以理解为排列组合中的分步进行思想,每一步选择质数pi的指数数ai,得出因子数

还有第二个推论:

n!质因数分解:给出正整数n,求n阶乘的因数,

由于n!的特殊性,可以发现小于等于n的质数一定都是n!的质因数,大于n的质数一定不是。那么先打出质数表。对于质数ei,在n!的分解式中的指数ki=n/ei+n/ei^2+……+n/ei^x,其中n>=ei^x

即n!中有ki个ei,这个通过枚举ei,ei*2,....ei*ei,ei*ei*2.....n,能大致猜测到怎么样得出这个结论的,但具体证明还是

想不太出来。。。

接下来题目:

求组合数C(N,M),以及C(N,M)因子个数。

求因子数大致用上述模板即可,但是求组合数过程中,n!会爆ll,所以要便运算便约分,模板如下

ll c(int n,int m)
{
	ll a=1,b=1;
	if(n-m<m){
		m=n-m;//通过组合数性质简化
	}
	for(int i=1;i<=m;i++){ 
		a*=(n-i+1);     //n!/(n-m)!
		b*=i;
		if(a%b==0){
			a/=b;   //边运算边约分
			b=1;
		}
	}
	return a/b;             //上式与下式相除
}

求c(n,m)因子数,看了别人的博客,才明白可以把n!/(m!*(n-m)!)作为整体,来求它的质数ei的指数,至于怎么求,

显然这个整体c,是由上式一部分和下式两部分组成,求c对ei的指数,则可以求上式ei的指数再减去下式的,作为c对ei的指数

最后套用n的因数定理得出结果

ac代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
bool isprime[55];//素数表
ll c(int n,int m)
{
	ll a=1,b=1;
	if(n-m<m){
		m=n-m;
	}
	for(int i=1;i<=m;i++){
		a*=(n-i+1);
		b*=i;
		if(a%b==0){
			a/=b;
			b=1;
		}
	}
	return a/b;
}
ll divisors(int n,int p)//求对ei的指数
{
	int ans=0;
	int temp=p;
	while(n/p){
		ans+=(n/p);
		p*=temp;
	}
	return ans;
}
int main()
{
	memset(isprime,true,sizeof(isprime));//最近才知道的小技巧,比0,1好用
	int n,m;
	for(int i=2;i<=50;i++){
		if(isprime[i]){
			for(int j=i+i;j<=50;j+=i){//简单的素数筛
				isprime[j]=false;
			}
		}
	} 
	while(~scanf("%d %d",&n,&m)){
		ll ans=c(n,m);
		ll sum=1;
		for(int i=2;i<=n;i++){
			if(!isprime[i]) continue;
			int p=i; 
			sum*=(divisors(n,p)-divisors(m,p)-divisors(n-m,p)+1);//因数的定理
		}
		cout<<ans<<" "<<sum<<endl;
	}
	return 0;
} 

总体来讲,还是学到一些数论的知识以及技巧

参考博客:https://blog.csdn.net/qq_39439314/article/details/78270905

                  https://blog.csdn.net/wentong_Xu/article/details/81669736

                  https://blog.csdn.net/u013081425/article/details/24597979

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值