题意:寻找1 ~ N中能表示成 M K M^K MK,其中M和K都是正整数并且K>1的这样的数的个数。
思路: N很大,枚举N是不可能了。但它既然表示成 M K M^K MK,我们就枚举K就好了。因为除了1,M最小也就取到2,而2的64次方就已经超过N的范围了。所以K最大就取到64。至于具体怎么枚举,我们可以让K从2循环到64,当K=2时,满足情况的M有1,2,… , N \sqrt{N} N,一共就这 N \sqrt{N} N个,因为再大的话乘方之后就大于N了。当K=3时,满足情况的M有1,2,……, N 3 \sqrt[3]{N} 3N,一共有 N 3 \sqrt[3]{N} 3N个。同理,K等于4,5,… ,64时,满足情况的M分别就有 N 4 , N 5 , … , N 64 \sqrt[4]{N},\sqrt[5]{N},… ,\sqrt[64]{N} 4N,5N,…,64N个。但我们要注意,当我们把K=2的情况都加上之后,K=4的情况就没必要再加了。因为 N 4 = N 2 2 \sqrt[4]{N}=\sqrt[2]{\sqrt[2]{N}} 4N=22N。同理,当K=6的时候, N 6 = N 3 2 = N 2 3 \sqrt[6]{N} = \sqrt[2]{\sqrt[3]{N}}=\sqrt[3]{\sqrt[2]{N}} 6N=23N=32N,所以我们找K=2,K=3时相当于都把K=6的情况多找了一遍,因此我们要把这种情况减掉。所以最后的答案就是 N 2 + N 3 + 0 ∗ N 4 + N 5 − N 6 … \sqrt[2]{N} + \sqrt[3]{N} + 0*\sqrt[4]{N} + \sqrt[5]{N} - \sqrt[6]{N}… 2N+3N+0∗4N+5N−6N…,看它们的系数是不是很熟悉?没错,就是莫比乌斯函数的相反数,因此我们可以先离线把前64位的莫比乌斯函数筛出来,然后用它的相反数乘上每一项的个数加起来就是最后的答案了。不过因为每一次都算上了1,我们可以先将答案初始化成1,就是先把1加上,之后的每一项就都把1减掉就可以了。刚开始的时候我没考虑到1,就直接算了,巧合的是结果都比答案大1,我直接用我算的结果减1交上,还真对了。但我没想明白为什么,希望路过的大佬可以帮帮我,QAQ
下面是我的代码
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long int ll;
const int maxn = 199;
ll mu[maxn + 10], prime[maxn + 10];
bool vis[maxn + 10];
void Moblus()
{
mu[1] = 1;
for(int i = 2; i < maxn; ++ i)
{
if(!vis[i])
{
prime[++ prime[0]] = i;
mu[i] = -1;
}
for(int j = 1; j <= prime[0] && i * prime[j] < maxn; ++ j)
{
vis[i * prime[j]] = true;
if(i % prime[j] == 0)
{
mu[i * prime[j]] = 0;
break;
}
else
{
mu[i * prime[j]] = -mu[i];
}
}
}
}
int main()
{
//freopen("in.txt", "r", stdin);
ll n, ans;
Moblus();
while(cin >> n)
{
ans = 1;
for(ll i = 2; i <= 64; ++ i)
{
ans -= mu[i] * ((ll)pow(n, 1.0 / i) - 1);
}
cout << ans << endl;
// ans = 0; //这是我第一次写的,也AC了。
// for(int i = 2; i <= 64; ++ i)
// {
// ans -= (mu[i] * (ll)pow(n, 1.0 / i));
// }
// cout << ans - 1 << endl;
}
return 0;
}