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\)数组就是一个莫比乌斯函数😨。

posted @ 2018-05-23 21:38  pfy_pfy  阅读(150)  评论(0编辑  收藏  举报