20180523模拟赛T4——Number
【题目描述】
最近𝐴𝑛𝑠𝑤𝑒𝑟正在研究“幂次数”,一个正整数被称为“幂次数”当且仅当存在\(x = y^k(y> 0, k > 1)\)。
好奇的𝐴𝑛𝑠𝑤𝑒𝑟想要知道在1~𝑵中有多少数是幂次数。
【输入格式】
输入文件number.in包含 1个正整数𝑵
【输出格式】
输出文件 number.out包含一个非负整数表示1~𝑵中幂次数的个数
【样例输入1】
10
【样例输出1】
4
【样例解释】
1~10中的幂次数有 1,4,8,9
【样例输入2】
36
【样例输出2】
9
【数据规模】
对于\(40\%\)的数据,$N \le 10^6 $
对于\(70\%\)的数据,$N \le 10^{12} $
对于\(100\%\)的数据,$N \le 10^{18} $
题解
听说这题有\(10^{18}\)种过题方法,巧了,我只会\(10^{18}\%10\)种。
yk:我们发现这个是莫比乌斯函数的经典模版,套一个莫比乌斯函数就可以了。orz
先copy一下yk的题解:
40分,暴力枚举每个数,把所有是这个数的a次方的数打上标记,然后统计
60分,类似线性筛的暴力,发现只有<=sqrt(n)的数的a次方才对答案有贡献
发现已经是某个数的a次方的数对答案无贡献,然后筛过去即可
100分 考虑容斥原理
对于每个i,a ^ i <= n可以通过二分获得答案
对于a ^ 3 <= n,我们发现会跟a ^ 2 <= n有重复,
比如 (a ^ 2) ^ 3=(a ^ 2) ^ 3
所以要减去a^6<=n的个数
我们发现这个是莫比乌斯函数的经典模版,套一个莫比乌斯函数就可以了
O(log(n)^3) 加一些优化可以到 O(log(n)^2)
不过似乎其他人都不是这样做的
由于我比较菜,只会yyhhenry的方法。
本题可以用容斥做。对于\(y = x^k(y\le n)\),我们发现\(y\)的个数为\(\lfloor\sqrt[k]{n}\rfloor\),于是我们发现可以用容斥做。
那么先看一下我的代码(只贴了主函数,sqrt用二分或牛顿迭代法):
LL yyh[65];
int main()
{
fin >> n;
LL ans = 1;
for(int i = 2; i <= 64; ++i)
{
LL b = 1-yyh[i];
for(int j = i; j <= 64; j += i)
yyh[j] += b;
ans += (sqrt(i)-1) * b;
}
fout << ans << '\n';
return 0;
}
枚举到64是因为\(2^{64}\)已经是数据的极限了。而\(yyh\)数组枚举的是\(k = i\)时每一种状态被多算的情况的情况。根据容斥原理,没个数我们只能枚举一次。而由于枚举了\(yyh[i]\)次,所以真正需要枚举的是\(1-yyh[i]\)次(注意可能是负数)。我们再将\(b\)乘以我们刚才推出来的\(\lfloor \sqrt[k]{n}\rfloor\),就得到了真正没有重复的答案。此外,对于状态\(j\mid i\),由于\(j\)状态时要多算一遍,于是我们就把\(yyh[j]\)加上\(b\)。
是不是觉得很精妙?
听说\(yyh\)数组就是一个莫比乌斯函数😨。