数学——质因数分解、互质

P1069 [NOIP2009 普及组] 细胞分裂 T3

#include <bits/stdc++.h>
using namespace std;
int n, s[10010], m1, m2, cnt, prim[3246], target[3246];
double curans, ans=1e9;
//打表计算 30000 以内的质数, 并存在数组prim中 
inline void ini()
{
	for(int i=2; i<30000; ++i){
		bool flag=true;
		for(int j=2; j<=sqrt(i); ++j){
			if(i%j==0){
				flag=false;
				break;
			}
		}
		if(flag){
			cnt++;
			prim[cnt]=i;
		}
	}
} 
int main()
{
	ini();
	cin >> n >> m1 >> m2;
	for(int i=1; i<=n; ++i){
		scanf("%d", &s[i]);
	}
	//如果m1等于1, 则无法质因数分解, 不需要任何分裂, 可以直接将细胞放进去即可 
	//注意这一段特判不能放在对m1质因数分解后面, 因为m1质因数分解以后肯定为1 
	if(m1==1){
		puts("0");
		return 0;
	} 
	//对m1进行质因数分解
	for(int i=1; i<=cnt && m1>1; ++i){
		while(m1%prim[i]==0){
			target[i]+=m2;	//target[i] 记录m1的m2次方里面总共有多少个质因数 prim[i] 
			m1/=prim[i];
		}
	}
	for(int i=1; i<=n; ++i){	//枚举每一种细胞 
		bool flag=true;
		for(int j=1; j<=cnt; ++j){	//枚举所有的质因数 
			//s[i]无法整除m1中的质因数prim[j], 第i种细胞始终无法实现目标 
			if(target[j]!=0 && s[i]%prim[j]!=0){
				flag=false;
				break;
			}
		}
		if(flag==true){
			//对s[i]进行质因数分解
			curans=0;
			//枚举m1的m2次方中所有的质因数 
			for(int j=1; j<=cnt && s[i]>1; ++j){
				double asd=0;	//记录s[i]中有几个质因数prim[j] 
				//只分解有用的质因数 
				while(target[j] && s[i]%prim[j]==0){
					asd++;
					s[i]/=prim[j];
				}
				curans=max(curans, ceil(target[j]/asd));
			}
			if(curans!=0){
				ans=min(ans, curans);
			}
		} 
	} 
	if(ans==1e9){
		printf("-1");
	}
	else{
		printf("%.0lf", ans);
	}
	return 0;
}

P1414 又是毕业季II   因数分解一道题目,降复杂度的思路妙

#include <bits/stdc++.h>
using namespace std;
int n, a[10010], mx, cnt[1000010];
int main()
{
	scanf("%d", &n);
	for(int i=1; i<=n; ++i){
		scanf("%d", &a[i]);
		mx=max(mx, a[i]);
	} 
	//统计每个因数出现的次数, 传统的根号优化 
	for(int i=1; i<=n; ++i){
		for(int j=1; j<=sqrt(a[i]); ++j){	//这里粗心把sqrt(a[i])写成sqrt(i)了 
			if(a[i]%j==0){
				cnt[j]++;
				if(j*j!=a[i]){
					cnt[a[i]/j]++;
				}
			}
		}
	}
	//因为数字越大, 出现为因子的次数越少, 所以cnt数组是倒序的 
	//这么写能够降低复杂度, 复杂度降到了O(mx) 
	for(int i=1; i<=n; ++i){
		//如果大的mx作为因数出现的次数不够i次, 那更不可能够i+1次 
		while(cnt[mx]<i){
			mx--;
		}
		printf("%d\n", mx);
	}		
	return 0;
}

P1072 [NOIP2009 提高组] Hankson 的趣味题  枚举,gcd lcm推式子后能降低枚举的复杂度

#include <bits/stdc++.h>
using namespace std;
int n, a0, a1, b0, b1, ans, k1, k2, p1, p2, x0; 
int main()
{
	scanf("%d", &n);
	while(n--){
		scanf("%d %d %d %d", &a0, &a1, &b0, &b1);
		ans=0;
		//x和a0的最大公约数为a1, x=k1*a1, a0=k2*a1, k1 k2互质 
		k2=a0/a1;
		//x和b0的最小公倍数为b1, b1=p1*x, b1=p2*b0, p1 p2互质
		p2=b1/b0;
		//枚举x验证是否满足两个互质条件
		//注意:虽然x是大于等于a1的, 但是枚举时得从1开始, 不然就漏掉了b1那些大因子 
		for(int x=1; x<=sqrt(b1); ++x){
			if(b1%x==0){ 
				x0=b1/x;
				if(x%a1==0){
					k1=x/a1;
					p1=b1/x;
					if(__gcd(k1, k2)==1 && __gcd(p1, p2)==1){
						ans++;
					}
				}
				if(x!=x0 && x0%a1==0){
					k1=x0/a1;
					p1=b1/x0;
					if(__gcd(k1, k2)==1 && __gcd(p1, p2)==1){
						ans++;
					}
				}
			} 
		}
		printf("%d\n", ans);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ypeijasd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值