PTA:2-4 素因子分解 (20 分)

题目详情:

给定某个正整数 N,求其素因子分解结果,即给出其因式分解表达式 N=p1​k1​⋅p2​k2​⋯pm​km​。

输入格式:

输入long int范围内的正整数 N。

输出格式:

按给定格式输出N的素因式分解表达式,即 N=p1^k1*p2^k2*…*pm^km,其中pi为素因子并要求由小到大输出,指数kipi的个数;当ki为1即因子pi只有一个时不输出ki

输入样例:

1323

结尾无空行

输出样例:

1323=3^3*7^2

结尾无空行

这个毒瘤题可把我害惨了,因为一小测试点卡了两小时。。。(一会儿解释)

首先最直接的想法当然是找素数咯,枚举2到n的素数,然后判断。。。

打住!这么暴力肯定过不了。蒙受大佬线性筛素数的启发,我们可以先用线性筛找到所有素数。再从小的开始找。不过,得把筛素数和本题结合一下,我们要找n的质因数,从2枚举到n,每一次都除i,直到不能除为止,并且记录它的次数。我们会发现只有素数才会计数,合数是不会计数的。以2为例,我们已经将n除了2(除到不能再除),n一定就不会被2的倍数整除。可以证明:n%m!=0,则n%(k*m)!=0. 于是一个循环的过程中我们既做了筛选,又记录了素数的次数。

这样就行了吗?no!还有一个问题,直接开一个long int的数组,可能会溢出。于是我采用将<素数--出现次数>键值对存入map中,解决了浪费空间的问题。

代码(初始):

#include<iostream>
#include<map>
using namespace std;
typedef long int li;
int main()
{
	map<li,int>mp;
	ios::sync_with_stdio(0);  //加一下速,之后输出会比较多
	li n;
	cin>>n;
	li t=n;
	for(li i=2;i<=n;i++){
		while(t%i==0){
			if(mp.count(i)) mp[i]++;
			else mp.insert(pair<li,int>(i,1)); //这两行可以简化为mp[i]++;
			t/=i;
		}
		if(t==1) break; //如果已经分完了及时退出
	}
	cout<<n<<"=";
	map<li,int>::iterator last=mp.end();
	last--;   //一个元素输出单独处理,输出没有*
	for(map<li,int>::iterator it=mp.begin();it!=last;it++)
	if(it->second>1) cout<<it->first<<"^"<<it->second<<"*";
	else cout<<it->first<<"*";  //要判断指数是否为1
	if(last->second>1) cout<<last->first<<"^"<<last->second;
	else cout<<last->first;
	return 0;
}

运行结果:

what’s up? 为什么有一个1分的测试过不了?这就是最毒的地方。我尝试过改迭代器没有用,以为是数据量的问题就全部改为long long但任然过不了。

大部分的测试点没有问题,也不是数据类型的问题。真相只有一个!某一个特殊的数据,执行这个程序时,会出现指针越界!这个数很显然是n=1.这个时候map为空,执行last--,后面迭代器会访问到非法位置。

 加上这句就好啦:

if(n==1){
		cout<<"1=1";
		return 0;
	}

最终代码:

#include<iostream>
#include<map>
using namespace std;
typedef long int li;
int main()
{
	map<li,int>mp;
	ios::sync_with_stdio(0);
	li n;
	cin>>n;
	li t=n;
	if(n==1){
		cout<<"1=1";
		return 0;
	}
	for(li i=2;i<=n;i++){
		while(t%i==0){
                               mp[i]++;
			t/=i;
		}
		if(t==1) break;
	}
	cout<<n<<"=";
	map<li,int>::iterator last=mp.end();
	last--;
	for(map<li,int>::iterator it=mp.begin();it!=last;it++)
	if(it->second>1) cout<<it->first<<"^"<<it->second<<"*";
	else cout<<it->first<<"*";
	if(last->second>1) cout<<last->first<<"^"<<last->second;
	else cout<<last->first;
	return 0;
}

运行结果:

终于ac了!qwq.

  • 13
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值