【PAT甲级】1059 Prime Factors (25分)

解题过程的小记录,如有错误欢迎指出。

难度:三星(找素数模板+找因数模板)

题目分析

给出一个数n,找出它的素数因数队列

注意点

  1. 题干说的是n为正整数范围,所以要考虑1的情况
  2. 题干说n是long int,要考虑过程中是否有溢出(我把涉及的变量都改为long long了,可以过)

我的解题过程

思路

  1. 找出<=sqrt(n)的质数【n的质因数一定全部<=sqrt(n)或者有一个大于】
  2. 确认找出的质数是否是n的因数,如果是的话,有几个
  3. 按格式输出
    【本题还是要看看自己的代码,有挺多值得注意的点】

bug

  1. 刚开始没考虑n=1的情况
  2. 在大于开方数的质因数的添加情况下忘记计数了

代码

#include<iostream>
#include<math.h>
#include<vector>

using namespace std;
typedef long long LL;

struct Factor {//因数结构:记录素数因数本身和它出现的次数
	LL prime, cnt = 0;
};

bool isPrime(LL num) {//判断是否是素数
	if (num <= 1) return false;
	for (LL i = 2; i <= (LL)sqrt(num*1.0); i++) {//这里一定要写出<=,不然25会被当成素数
		if (num%i == 0) return false;
	}
	return true;
}

int main()
{
	LL n;
	cin >> n;
	if (n == 1) {//有一个测试点专门测试为1的情况,如果不考虑则过不了
		printf("1=1");
		return 0;
	}
	LL fcnt = 0, num = 2, temp = n;
	vector<Factor> factor;
	while (num <= (LL)sqrt(1.0*n)) {//找出数n可能的素数因数,必然<=n的开方,如有大于的也只有一个
		if (isPrime(num)) {
			Factor f;
			f.prime = num;
			factor.push_back(f);
			fcnt++;
		}
		num++;
	}
	for (LL i = 0; i < fcnt; i++) {//确认各素数是否是数n的因数,如果是求出个数
		while (n%factor[i].prime == 0) {
			factor[i].cnt++;
			n /= factor[i].prime;
		}
		if (n == 1) break;//当所有因数都被找到了就不再找了(这句话可以节省一点时间
	}
	if (n != 1) {//如果n没有被<=sqrt(n)的因数除尽,那么就说明还有一个大于其开方的因数
		Factor f;
		f.prime = n;
		f.cnt++;
		factor.push_back(f);//把该因数计一次加入因数列
	}
	bool iseverprit = false;//用于判断是否要输出'*'
	printf("%lld=", temp);
	for (LL i = 0; i < factor.size(); i++) {
		if (factor[i].cnt == 0) continue;
		else {
			if (iseverprit) printf("*");
			printf("%lld", factor[i].prime);
			if (factor[i].cnt > 1) printf("^%lld", factor[i].cnt);
			iseverprit = true;
		}
	}
    return 0;
}

dalao的代码

全部代码因版权原因不放出来,大家可以自行去柳神博客购买或者参考晴神的上机笔记~

借鉴点

  1. 不要把循环体内会发生改变的值放在判断条件里,为了避免这个发生,以后涉及sqrt(n)的操作都用另外一个变量来存储
  2. 在找因数循环体内,n被除尽为1时就可以break,这样可以节省一丢时间
		if (n == 1) break;//当所有因数都被找到了就不再找了(这句话可以节省一点时间
  1. emmm本题看晴神的实战代码就好,如果有不理解可以去看对应篇章的笔记
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值