CF955C Sad powers 题解

Content

给你 \(q\) 个询问,每次询问 \([l,r]\) 这个区间内满足 \(x=a^p(a>0,p>1)\)\(x\) 的数量。

数据范围:\(1\leqslant q\leqslant 10^5\)\(1\leqslant l\leqslant r\leqslant 10^{18}\)

Solution

第一次自己独立做出了紫题,特此发篇题解纪念一下。

首先,我们看到数据范围是 \(10^{18}\) 级别的,看到次幂,然后联想到 \(\sqrt{10^{18}}=10^9\)\(\sqrt[3]{10^{18}}=10^6\)。然后我们发现,如果 \(p\geqslant 3\) 的话,貌似可以直接预处理出所有的满足题目要求的 \(x\),询问时直接二分其位置即可。至于 \(p=2\) 的情况(事实上就是完全平方数),由于 \(x\) 以内的完全平方数个数为 \(\sqrt{x}\),因此利用类似前缀和的思想就可以求出这一部分的答案为 \(\sqrt{r}-\sqrt{l-1}\)。两个部分综合在一起即可求出答案。

具体实现的时候要注意答案的边界问题以及直接开根带来的精度问题。

Code

请注意,以下代码仅可在 C++14 语言下通过。原因可能是 sqrt 容易掉精度。

namespace Solution {
	const int N = 3e6 + 7;
	const ll MX = 1e18;
	int q, cnt;
	ll l, r, num[N];
	
	ill solve(ll x) {
		ll idx = lower_bound(num + 1, num + cnt + 1, x) - num;
		if((idx <= cnt && num[idx] > x) || idx > cnt) idx--;
		return idx + (ll)sqrt(x);
	}
	
	iv Main() {
		F(ll, i, 2, 1000000) {
			long long k = i * i;
			for(; k <= MX / i; ) {
				k *= i;
				ll sqrtk = sqrt(k);
				if(sqrtk * sqrtk != k) num[++cnt] = k;
			}
		}
		sort(num + 1, num + cnt + 1), cnt = unique(num + 1, num + cnt + 1) - num - 1;
		read(q); while(q--) read(l, r), print(solve(r) - solve(l - 1), '\n');
		return;
	}
}
posted @ 2021-12-15 21:14  Eason_AC  阅读(148)  评论(0)    收藏  举报