HDOJ2204
每天都来补题确实很充实,类型都不一样
大概思路都会,就是写不对的题,才会目前来说最重要最有意义的题了吧
http://acm.hdu.edu.cn/showproblem.php?pid=2204
给定n,求1-n中有多少个可以表示成M的K次方的数。K>1
题意很简单,但是怎么想?题面上说到了素数,第一想法就是K从素数开始枚举!
当K不是素数时,必然是重复算过的!比如K=6时,一定会有一个(M1的2次方)的3次方=(M2的3次方)的2次方
那么,最大素数是多少?n最大值是1e18,所以呢,找到一个x,使得2的x次方大于n的最大值,x=60
所以取61为最大素数肯定满足条件了
可以枚举了?
还是要注意容斥!
例如15=3*5,所以,3的要加,5的要加,15的要减
最多是几层?
2*3*5=30
2*3*5*7=210已经大于60了,所以最多枚举三重循环就好
现在是有了n和K,怎么得到M呢?
只需要这一行代码:
tmp=(int)(pow((double)n,1.0/prime[i])+eps);
最后1个问题:1的K次方都是满足条件的
所以,注意:一开始ans赋初始化就为1,之后,所有的计算把1除掉就好
代码:
bool p[maxn];
int prime[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97};
int all=25;
int main(){
//input;
long long n;
int i,j,k,ans,tmp;
while(scanf("%I64d",&n)!=EOF){
ans=1;
for(i=0;i<all;i++){
tmp=(int)(pow((double)n,1.0/prime[i])+eps);
ans+=tmp-1;
}
for(i=0;i<all;i++)
for(j=i+1;j<all;j++){
tmp=(int)(pow((double)n,1.0/(prime[i]*prime[j]))+eps);
ans-=tmp-1;
}
for(i=0;i<all;i++)
for(j=i+1;j<all;j++)
for(k=j+1;k<all;k++){
tmp=(int)(pow((double)n,1.0/(prime[i]*prime[j]*prime[k]))+eps);
ans+=tmp-1;
}
printf("%d\n",ans);
}
return 0;
}