这是一个很菜的 Oier 的博客|

Hanx16Msgr

园龄:2年8个月粉丝:12关注:3

2023-03-07 13:23阅读: 121评论: 0推荐: 0

CF955C Sad powers

CF955C Sad powers

Luogu CF955C

题面翻译

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

数据范围:

  • 1q105
  • 1lr1018

Translated by Eason_AC
2021.10.8

题目描述

You're given Q queries of the form (L,R) .

For each query you have to find the number of such x that L<=x<=R and there exist integer numbers a>0 , p>1 such that x=ap .

输入格式

The first line contains the number of queries Q (1<=Q<=105) .

The next Q lines contains two integers L , R each (1<=L<=R<=1018) .

输出格式

Output Q lines — the answers to the queries.

样例 #1

样例输入 #1

6
1 4
9 9
5 7
12 29
137 591
1 1000000

样例输出 #1

2
1
0
3
17
1111

提示

In query one the suitable numbers are 1 and 4 .

Solution

2023 春赛观光团。

对于一个询问 [l,r],显然可以拆成 [1,r][1,l1] 两部分计算。

考虑 [1,n] 如何计算。由于指数的值域很小,因此可以考虑枚举指数来计算答案。

fi 表示满足 ain 的数量(不考虑与其他指数重复的情况),那么显然可以得知 fi=ni。考虑如何容斥掉重复的部分,直接容斥貌似不好做,因此考虑钦定一个数的唯一指数表示方式。

对于一个数 t,假设 t=a1p1=a2p2(p1>p2),那么将 t 的表示方法钦定为 t=a1p1,即指数最大的一个。容易发现,对于所有可以组成 t 的指数 p 都有 pip1。那么按照这种钦定方法下,记每个指数对答案的贡献是 ansi,那么有 ansi=fiijansj。从大到小计算即可。时间复杂度是 O(log2n) 级别的。

代码实现的时候有一个很麻烦的东西,就是 ni 如何计算。如果使用 n1/i 计算会出现很大的精度问题;如果用二分计算的话时间会超时。因此有一个折中的办法,就是先用 n1/i 计算,然后再暴力判断计算出来的这个值 v 接近的值是否满足答案,即判断一下 v+1,v1,v+2,v2, 是否符合条件,然后卡一下精度就过了。

Code

#include<bits/stdc++.h>
#define int long long

using namespace std;

int l, r;
int a[100005];

inline long double Qpow(int x, int y) {
	long double res = 1, base = x;
	
	for (; y; y >>= 1, base *= base) {
		if (y & 1) {
			res *= base;
		}
	}
	
	return res;
}

inline int GetRoot(int x, int y) {
	int v = powl(x, (long double)1.0 / y + 1e-9);
	
	if (Qpow(v + 1, y) < x) 
		for (++v; Qpow(v + 1, y) < x; ++v);
		
	if (Qpow(v, y) > x)
		for (--v; Qpow(v, y) > x; --v);
	
	return v;
}

int Calc(int n) {
	if (n == 0) return 0;
	
	int res = 1;
	int lim = 0;
	
	for (int i = 2; ; ++i) {
		int v = GetRoot(n, i);
		lim = i;
		
		if (v <= 1) break;
		
		a[i] = v - 1;
	}
	
	for (int i = lim - 1; i >= 2; --i) {
		for (int j = i + i; j < lim; j += i) {
			a[i] -= a[j];
		}
	}
	
	for (int i = 2; i < lim; ++i) {
		res += a[i];
	}
	
	return res;
}

void Solve() {
	cin >> l >> r;
	cout << Calc(r) - Calc(l - 1) << '\n';
}

signed main() {
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int T; cin >> T;
	
	while (T--) Solve();
}
posted @   Hanx16Msgr  阅读(121)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起