唯一分解定理的应用

一个数的唯一分解为
n的唯一分解

1. 一个数的所有因子个数: x = ( e 1 + 1 ) ( e 2 + 1 ) . . . . . . . ( e k + 1 ) x=(e1+1)(e2+1).......(ek+1) x=(e1+1)(e2+1).......(ek+1)

2. 一个数的所有因子和:
一个数的所有因子和

3. 用唯一分解求a,b的gcd,lcm(ak,bk为质数的幂):
g c d ( a , b ) = p 1 m i n ( a 1 , b 1 ) p 2 m i n ( a 2 , b 2 ) . . . . . . p k m i n ( a k , b k ) gcd(a,b)=p_{1}^{min(a1,b1)}p_{2}^{min(a2,b2)}......p_{k}^{min(ak,bk)} gcd(a,b)=p1min(a1,b1)p2min(a2,b2)......pkmin(ak,bk)
l c m ( a , b ) = p 1 m a x ( a 1 , b 1 ) p 2 m a x ( a 2 , b 2 ) . . . . . . p k m a x ( a k , b k ) lcm(a,b)=p_{1}^{max(a1,b1)}p_{2}^{max(a2,b2)}......p_{k}^{max(ak,bk)} lcm(a,b)=p1max(a1,b1)p2max(a2,b2)......pkmax(ak,bk)

4.在不取mod的情况下,用唯一分解求组合数
C ( n , m ) = n ! / ( m ! ∗ ( n − m ) ! ) C(n,m)=n!/(m!*(n-m)!) C(n,m)=n!/(m!(nm)!)
用唯一分解求出分母和分子的唯一分解,然后约分,约掉素因子就不会爆long long范围。
拓展:如果给题目给你一个素数mod,就可以用阶乘逆元求.。

素数筛:

const int N=1e6+5;
int p[N],k=0;
bool vis[N];
void prime(int n){
	memset(vis,0,sizeof(vis));
	int m=(int)sqrt(n+0.5);
	for(int i=2;i<=m;i++)if(!vis[i])
		for(int j=i*i;j<=n;j+=i)vis[j]=1;//写j=i*i,,比2*i更快,而且效果相同
		
	for(int i=2;i<=n;i++)if(!vis[i])p[k++]=i;
}
  • 求一个数的所有因子个数(LightOJ1341)
#include<cstdio>
#include<iostream>
#include<algorithm> 
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;

const int N=1e6+5;
int p[N],k=0;
bool vis[N];
void prime(int n){
	memset(vis,0,sizeof(vis));
	int m=(int)sqrt(n+0.5);
	for(int i=2;i<=m;i++)if(!vis[i])
		for(int j=i*i;j<=n;j+=i)vis[j]=1;
		
	for(int i=2;i<=n;i++)if(!vis[i])p[k++]=i;
}

ll cal(ll x){//算x的因子个数                                                                                                                                                                                                                                                                                                                                                                                                                                       
	ll cnt=1,t;
	for(ll i=0;p[i]*p[i]<=x&&i<k;i++){//p[i]*p[i]<=x比p[i]<=x省下更多时间 
		if(x%p[i]==0){
			t=0;
			while(x%p[i]==0){x/=p[i],t++;}
			cnt*=(t+1);
		} 
	}
	if(x>1)cnt*=2;
	return cnt;
} 

int main(){
	prime(N);
	int t,kas=0;
	scanf("%d",&t);
	ll a,b;
	while(t--){
		scanf("%lld%lld",&a,&b);
		if(b*b>=a)printf("Case %d: 0\n",++kas);//写等于号因为题目说不是正方形 
		else {		
			ll ans=cal(a)/2;
			for(int i=1;i<b;i++)if(a%i==0)ans--;		
			printf("Case %d: %lld\n",++kas,ans);
		}	
	}
}
  • 求一个数所有因子的和
    1.(LightOJ1336)
    详细思路别的博客有,关键在于这个公式的推导
    ( p e + 1 − 1 ) / ( p − 1 ) (p^{e+1}-1)/(p-1) (pe+11)/(p1)
    = ( p e + 1 − p + ( p − 1 ) ) / ( p − 1 ) =(p^{e+1}-p+(p-1))/(p-1) =(pe+1p+(p1))/(p1)
    = p ( p e − 1 ) / ( p − 1 ) + 1 =p(p^{e}-1)/(p-1)+1 =p(pe1)/(p1)+1 (等比数列公式)
    = ( p + p 2 + p 3 . . . . . + p e ) + 1 =(p^{}+p^{2}+p^{3}.....+p^{e})+1 =(p+p2+p3.....+pe)+1

    因为p是奇数,由上可知,当e为偶数时,原式为奇数。反之相反;
#include<cstdio>
#include<iostream>
#include<algorithm> 
#include<cmath>
#include<cstring>
#define N 1000005
using namespace std;
typedef long long ll;


int main(){
	int t,k=0;
	ll a;
	scanf("%d",&t);
	while(t--){
		scanf("%lld",&a);
		printf("Case %d: %lld\n",++k,a-(ll)sqrt(a)-(ll)sqrt(a/2));
		//减去范围内平方数的个数和平方数的2倍的个数										
	}
} 

2.(ZOJ4040)
题目题解

  • 用唯一分解求lcm(LightOJ1236)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;

const int N=1e7+100;
int p[N/10],k=0;
bool vis[N];
void prime(){
	memset(vis,0,sizeof(vis));	
	ll m=(ll)sqrt(N+0.5);
	for(int i=2;i<=m;i++)if(!vis[i])
		for(int j=i*i;j<N;j+=i)vis[j]=1;
	
	for(int i=2;i<N;i++)if(!vis[i])p[k++]=i;
}

ll cal(ll x){
	ll ret=1;
	for(int i=0;p[i]*p[i]<=x&&i<k;i++){
		if(x%p[i]==0){
			ll t=0;	
			while(x%p[i]==0){t++,x/=p[i];}
			ret*=2*t+1;
		}
	}
	if(x>1)ret*=3;
	ret/=2,ret++; 
	return ret;
}

int main(){
	prime();
	int t,kas=1;
	ll n;
	scanf("%d",&t);
	while(t--){
		scanf("%lld",&n);
		printf("Case %d: %lld\n",kas++,cal(n));
	}	
}

求组合数
1.没有mod,用唯一分解求(推荐练习UVA10375)

//求C(n,m),这不是题解
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath> 
using namespace std;
typedef long long ll;

const int N=1e6+100;
bool vis[N];
int p[N/10],tot=0,a[N/10];

void prime(int n){
	memset(vis,0,sizeof(vis)); 
	int m=(int)sqrt(n+0.5);
	for(int i=2;i<=m;i++)if(!vis[i])
		for(int j=i*i;j<n;j+=i)vis[j]=1;
	for(int i=2;i<n;i++)if(!vis[i])p[tot++]=i;	
}

void cal(int n,int flag){//计算阶乘的唯一分解 
	for(int i=0;i<tot&&p[i]<=n;i++){
		int temp=n,sum=0;
		while(temp){
			sum+=temp/p[i];
			temp/=p[i];
		}
		a[i]+=sum*flag; 
	}
} 

int main(){
	int n,m;
	prime(N);
	while(~scanf("%d%d",&n,&m)){
		ll ans=1;
		memset(a,0,sizeof(int)*(n+10));
		cal(n,1);cal(m,-1);cal(n-m,-1);
		for(int i=0;i<tot&&p[i]<=n;i++)
			ans*=(ll)pow(p[i],a[i]);//这里也可以用快速幂加速 
		printf("%lld\n",ans);
	}
} 

2.有素数mod,用阶乘逆元求

#include<cstdio>
typedef long long LL;

const LL N=1e5+10,mod = 1e9 + 7; //计算组合数取mod(mod为质数) 
LL fac[N],inv[N]; 

LL fp(LL a,LL b)
{
    LL ans = 1;
    while (b){
        if (b&1)ans = ans * a % mod;
        a = a*a % mod;
        b >>= 1;
    }
    return ans;
}
 
void init()
{
    fac[0] = inv[0] = 1;
    for (int i = 1;i<= N+100;i++)fac[i]=fac[i-1]*i%mod; 
    inv[N]=fp(fac[N],mod-2);
	for(int i=N;i>=1;i--)inv[i-1]=inv[i]*i%mod;
}

int main()
{
    init();
    int n,m;
    while (~scanf ("%d %d",&n,&m))
        printf ("%lld\n",fac[n] * inv[n-m] % mod * inv[m] % mod);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值