题目链接: hdu2204
题意:
给一正整数n
(1<=n<=1018)
, 求[1,n]中能表示成
MK(K>1)
的数的个数。
第一次好好看容斥,感觉智商已经不够了,看了好多题解才明白。。。
- 若 MK<=n 满足, 则任意m <= M 都满足 mK<=n ;
- 满足 MK 的数中,若K不是素数,则 MK=(Ma)p , 其中a*p = K且p是素数, 即满足题意的数都可以表示成 xp ,p是素数,答案仅需找出满足 xp 的个数;
-
xp
中有许多重复的,若
x=yq
(q是素数且
p≠q
),
(xp)q=(xq)p
, 例如
(62)3=(63)2
,
规律满足容斥原理, ans=f(p1)+...−f(p1∗p2)−...+... ; - 因为 260>1018 , 2*3*5*7 > 60, 所以所需最大素数为59,最高组合数不会过3个;
- 注意精度问题,虽说数据很水,不写也会过。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const double eps = 1e-9;
int p[17] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59};
LL n, ans;
void dfs(int cur, int ex, int pos)
{
if(pos > 3)
return;
for(int i = cur; i < 17; i++)
{
LL num = pow(n, 1.0/(p[i]*ex)) + eps;
num--;
if(num > 0)
pos&1? ans += num: ans -= num;
dfs(i+1, ex*p[i], pos+1);
}
}
int main(int argc, char const *argv[])
{
while(~scanf("%lld", &n))
{
ans = 0;
dfs(0, 1, 1);
printf("%lld\n", ans+1);
}
return 0;
}