题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=526
http://acm.hdu.edu.cn/showproblem.php?pid=2204
题目的意思很是简单让你求1 - n( n <= 10^18)中能够表示成M^k(k > 1)的数有多少个。。
分析发现,我们知道,k不会太大,所以,我们完全可以枚举素次幂。。
为什么要枚举素次幂。。因为合数次幂一定会包含在素次幂中。
比如 如果8^4在范围内,那么64^2肯定是在范围内的。。所以我们只需要枚举素次幂的数就好。。
还有,需要用到容斥原理。为什么?
因为64 = 8^2 = 4^3 = 2^6。。。所以需要减去应该减去的那部分。。
需要注意的是,精度是时候需要注意一下。。不过还是比较给力的在nyoj上的数据,给力。
Code:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
#define INT long long
const int N = 20;
const double eps = 1e-8;
const 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 _pow(INT a, INT k)
{
INT ans = 1;
while(k){
if(k & 1) ans = ans * a;
a = a * a;
k = k >> 1;
}
return ans;
}
INT F(INT n, INT tmp)
{
INT ans = pow((double)n, 1.0 / tmp) + eps;
if(pow(ans, 0.0 + tmp) > n) ans --;
if(ans < 1) ans = 1;
return ans - 1;
}
INT solve(INT n)
{
int p[N], top = 0;
for(int i = 0; i < 20; i ++){
if(_pow(2, prime[i]) <= n) p[top ++] = prime[i];
else break;
}
INT ans = 0;
for(int i = 1; i < (1 << top); i ++){
int cnt = 0;
INT tmp = 1;
for(int j = 0; j < top; j ++){
if(i & (1 << j)){
cnt ++;
tmp = tmp * p[j];
}
}
if(cnt % 2) ans += F(n, tmp);
else ans -= F(n, tmp);
}
return ans;
}
int main()//64
{
// freopen("1.txt", "r", stdin);
INT n;
while(cin >> n){
cout << solve(n) + 1 << endl;
}
return 0;
}
----->
容斥原理。2进制写法很是给力。。只不过,这种应该只针对小数据吧。。。