Codeforces Round 993 (Div. 4) E.Insane Problem
Codeforces 题解 - [Codeforces Round 993 (Div. 4) E.Insane Problem]
题目描述
Wave 获得了五个整数 \(k\) 、 \(l_1\) 、 \(r_1\) 、 \(l_2\) 和 \(r_2\) 。 Wave 希望你帮助她计算出有序对 \((x, y)\) 的数量,使得以下所有条件都得到满足:
- \(l_1 \leq x \leq r_1\) 。
- \(l_2 \leq y \leq r_2\) 。
- 存在一个非负整数 \(n\) 使得 \(\frac{y}{x} = k^n\) 。
输入格式
Input
The first line contains an integer \(t\) (\(1 \leq t \leq 10^4\)) — the number of test cases.
The only line of each test case contains five integers \(k\), \(l_1\), \(r_1\), \(l_2\), and \(r_2\) (\(2 \leq k \leq 10^9, 1 \leq l_1 \leq r_1 \leq 10^9, 1 \leq l_2 \leq r_2 \leq 10^9\)).
输出格式
Output
For each test case, output the number of matching ordered pairs \((x, y)\) on a new line.
题目大意
给你两个数的区间范围,寻找两个数均在区间范围且符合公式的有序对的数量。
输入
5
2 2 6 2 12
2 1 1000000000 1 1000000000
3 5 7 15 63
1000000000 1 5 6 1000000000
15 17 78 2596 20914861
输出
12
1999999987
6
1
197
解题思路
显然如果枚举x或者y求解有序对的方法, x 和 y 的取值范围[1, 1e9]。 第二个样例就会超时。
但是还有一个n可以进行暴力枚举。
为什么可以暴力枚举n呢?
得到
x, y的范围是[1, 1e9], k的范围是[2, 1e9]。
考虑到n最大的情况是 y = 1e9, x = 1, k = 2.
也就是说n最大的情况是 n = 30.
我们可以预处理所有\(k^n\), 枚举每个n,对于每个情况的n,我们可以二分最大的x,和最小的x(当然也可以二分y)。
每个时间复杂度是\(log(1e9) ≈ O(30)\).
每个例子的时间复杂度是\(O(log(xR−xL)) ≈ O(30 * log(1e9)) ≈ O(900)\).
总时间复杂度\(O(t×log(xR−xL)) ≈ O(9000000) ≈ O(1e6)\)
代码实现
#include "bits/stdc++.h"
using namespace std;
#define int int64_t
constexpr int Mod = 1e9 + 10;
int powK[50];
void Solution()
{
int xL, xR, yL, yR, k;
cin >> k >> xL >> xR >> yL >> yR;
int pairNum = 0;
auto Initialization = [&]()
{
powK[0] = 1;
for (int i = 1; i <= 31; ++i)
{
powK[i] = powK[i - 1] * k;
if(powK[i] > Mod) powK[i] = Mod;
}
return;
};
Initialization();
auto farLeft = [&](int miD, const int& kN)
{
int t = kN * miD;
// if (t > yR) return false;
//t < yL return true 太小 增大
//t == yL return false 尽可能小
//t > yL return false 还能小
return t < yL;
};
auto farRight = [&](int miD, const int& kN)
{
int t = kN * miD;
// if (t < yL) return true;
//t > yR return false
//t == yR return true;
//t < yR return ture;
return t <= yR;
};
for (int i = 0; i <= 30; ++i)
{
int kN = powK[i];
int lV, rV;
int lPtr = xL - 1, rPtr = xR + 1;
while (lPtr + 1 < rPtr)
{
int miD = lPtr + rPtr >> 1;
if (farLeft(miD, kN)) lPtr = miD;
else rPtr = miD;
}
lV = rPtr;
lPtr = xL - 1, rPtr = xR + 1;
while (lPtr + 1 < rPtr)
{
int miD = lPtr + rPtr >> 1;
if (farRight(miD, kN)) lPtr = miD;
else rPtr = miD;
}
rV = lPtr;
// cout << "lV = " << lV << " rV = " << rV << " val = " << rV - lV + 1 << '\n';
pairNum += rV - lV + 1;
}
// cout << "pairNum = ";
cout << pairNum << '\n';
return;
}
/*
1
0 1
*/
signed main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
// cout << (1LL * 1 << 1) << '\n';
int t;
cin >> t;
while (t--)
{
Solution();
}
return 0;
}
/*
1
53 644922653 836907643 264850321 782063425
*/

浙公网安备 33010602011771号