题目详情:
给定某个正整数 N,求其素因子分解结果,即给出其因式分解表达式 N=p1k1⋅p2k2⋯pmkm。
输入格式:
输入long int范围内的正整数 N。
输出格式:
按给定格式输出N的素因式分解表达式,即 N=p1^k1*p2^k2*…*pm^km
,其中pi
为素因子并要求由小到大输出,指数ki
为pi
的个数;当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.