Lightoj1220
题意:给你一个数n,要你求这个数可以是一个几次方数。
比如:n=64,
n
=
2
6
n=2^{6}
n=26,所以答案为6。
大多数人给的题解都是下面这种唯一分解的。把我坑惨了QAQ
为什么呢?我在比赛中碰到一个一样的题,但数据范围不一样n<=1e18,t<=100000
我比赛的时候就不停的往这个唯一分解这个方向想答案,一直想不出,因为你素数筛打表开不出1e9*int的空间,就算有这么大的空间,预处理也超时了,如果不预处理,那么也超时。。。。想了半天没做出来,比赛结果很遗憾TAT
如果比赛有重现赛的话我就把题目链接发出来。
- 唯一分解
//12ms过
//当数据量大,时这种做法就做不了了,时间空间都过不了。所以推荐用二分或者pow开根做
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
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=0;
bool sign=0;
if(x<0)x=-x,sign=1;
for(ll i=0;p[i]*p[i]<=x&&i<k;i++){
if(x%p[i]==0){
ll t=0;
while(x%p[i]==0){x/=p[i],t++;}
if(!cnt)cnt=t;
else cnt=__gcd(cnt,t);
}
}
if(x>1)cnt=1;//别写return cnt
if(sign)while(cnt%2==0)cnt/=2;
return cnt;
}
int main(){
prime(N);
int t,kas=0;
ll n;
scanf("%d",&t);
while(t--){
scanf("%lld",&n);
printf("Case %d: %lld\n",++kas,cal(n));
}
}
- 二分解法:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
// 1ms过
ll n;
int judge(ll x,int y){
ll temp=1;
for(int i=0;i<y;i++){
temp*=x;
if(temp>n)return 1;
}
if(temp<n)return -1;
return 0;//相等
}
int main(){
int t,kas=0;
scanf("%d",&t);
while(t--){
int ans=1;
scanf("%lld",&n);
bool f=1,flag=0;
if(n<0)n=-n,flag=1;
for(int i=33;i>=2&&f;i--){//从高次幂开始枚举,找到就退出
ll l=1,r=n;
while(l<=r){
ll mid=r+l>>1;
int temp=judge(mid,i);
if(temp==1)r=mid-1;
else if(temp==-1)l=mid+1;
else {
ans=i,f=0;
break;
}
}
}
if(flag)while(ans%2==0)ans/=2;
printf("Case %d: %lld\n",++kas,ans);
}
}
- pow开根
可以用pow(n,1/x)去开方然后判断,开方结果是否是整数,但是注意结果会产生浮点误差会导致你结果错误,不过误差不会很大,所以我们需要将结果在附近找,然后回代验算一下就好了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ios::sync_with_stdio(false);
int T,k=1;
cin>>T;
while(T--){
ll n;
cin>>n;
cout<<"Case "<<k++<<": ";
bool f=0;
if(n<0)f=1,n=-n;
int ans=0;
for(int i=32;i>=1;i--){
if(!(i&1)&&f)continue;
ll temp=(ll)pow(n,1.0/(double)i);
for(int j=-3;j<=3;j++)
if(n==(ll)pow(temp+j,i))ans=i;
if(ans){
cout<<ans<<endl;
break;
}
}
}
}