diff --git a/src/20241113/T538693.cpp b/src/20241113/T538693.cpp index 99494e8..aa7d153 100644 --- a/src/20241113/T538693.cpp +++ b/src/20241113/T538693.cpp @@ -1,18 +1,17 @@ #include #include +#include #include #include -#include #include #include #include #include -#include #include #include #include #include -#include +#include using int64 = std::int64_t; @@ -35,9 +34,9 @@ void print(Args&&...args){ struct Point{ int64 x, y; - bool operator<(const Point &that)const{ - return (this->x + this->y) < (that.x + that.y); - } + // bool operator<(const Point &that)const{ + // return (this->x + this->y) < (that.x + that.y); + // } bool operator==(const Point &that)const{ return this->x == that.x && this->y == that.y; } @@ -49,6 +48,7 @@ using Status = std::pair; const int64 max_n = 100 + 5; int64 _map[max_n][max_n]; const int64 (&map)[max_n][max_n] = _map; +std::bitset vis[max_n]; const std::array, 4> dir{{ {0, 1}, {1, 0}, @@ -71,19 +71,20 @@ int main(){ std::ranges::for_each(std::ranges::views::iota(1, n+1), [&](const auto &i){ std::ranges::for_each(std::ranges::views::iota(1,m+1), [&](const auto &j){ - input(_map[n][m]); + input(_map[i][j]); }); }); const double ansScore = input(); - std::priority_queue, std::greater<>> pq; - pq.emplace(Vector2{0, 0}, start); + std::queue q; + q.emplace(Vector2{0, 0}, start); + vis[start.x][start.y] = true; const Vector2 ansVec = [&]()->Vector2{ - while(!pq.empty()){ - const auto top = pq.top(); - pq.pop(); + while(!q.empty()){ + const auto top = q.front(); + q.pop(); if(top.second == end){ return top.first; @@ -91,15 +92,19 @@ int main(){ for (const auto i : dir) { const Point nextPoint = {top.second.x + i[0], top.second.y + i[1]}; - if(map[nextPoint.x][nextPoint.y] == 1 || nextPoint.x < 1 || nextPoint.x > n || nextPoint.y < 1 || nextPoint.y > m){ + if(map[nextPoint.x][nextPoint.y] == 1 || nextPoint.x < 1 || nextPoint.x > n + || nextPoint.y < 1 || nextPoint.y > m + || vis[nextPoint.x][nextPoint.y] + ){ continue; } - pq.emplace(Vector2{.x = top.first.x + std::abs(i[0]), .y = top.first.y + std::abs(i[1])}, nextPoint); + vis[nextPoint.x][nextPoint.y] = true; + q.emplace(Vector2{.x = top.first.x + std::abs(i[0]), .y = top.first.y + std::abs(i[1])}, nextPoint); } } throw std::runtime_error("unreachable"); }(); - const double udTimes = ansScore - (double)ansVec.x; - print(udTimes/ansVec.y); + const double udTimes = ansScore - (double)ansVec.y; + print(udTimes/ansVec.x); } \ No newline at end of file diff --git a/src/20241113/T538697.cpp b/src/20241113/T538697.cpp new file mode 100644 index 0000000..b80b8f9 --- /dev/null +++ b/src/20241113/T538697.cpp @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include +#include + +using int64 = int64_t; + +template +void input(Args&&...args){ + (std::cin>>...>>std::forward(args)); +} + +template +std::remove_cvref_t input(){ + std::remove_cvref_t t; + std::cin>>t; + return t; +} + +template +void print(Args&&...args){ + (std::cout<<...<(args)); +} + +const int64 max_n = 3e5 + 5; + +int main(){ + const int64 n = input(), m = input(); + + const std::array s = [&]()->std::remove_cvref_t{ + std::remove_cvref_t ret; + for(const auto &i : std::ranges::views::iota(1, n+1)){ + input(ret[i]); + } + return ret; + }(); + + +} \ No newline at end of file diff --git a/src/20241113/T538697.md b/src/20241113/T538697.md new file mode 100644 index 0000000..670c674 --- /dev/null +++ b/src/20241113/T538697.md @@ -0,0 +1,167 @@ +好的,下面是使用 C++ 解这道题的代码,主要思路和之前的 Python 解法类似,但我们会做一些适配以便在 C++ 中实现。 + +### C++ 解法 + +```cpp +#include +#include +#include +#include +#include + +using namespace std; + +const int MOD = 1e9 + 7; +const int MAX_VAL = 1e6; + +// 获取质因数 +vector getPrimeFactors(int x) { + vector factors; + for (int i = 2; i <= sqrt(x); ++i) { + while (x % i == 0) { + factors.push_back(i); + x /= i; + } + } + if (x > 1) { + factors.push_back(x); + } + return factors; +} + +int solve(int n, vector& a) { + // Step 1: 使用筛法计算每个数的质因数 + vector min_operations(MAX_VAL + 1, INT_MAX); + + // 遍历输入数组,更新每个数的最小操作次数 + for (int i = 0; i < n; ++i) { + int num = a[i]; + vector factors = getPrimeFactors(num); + for (int factor : factors) { + min_operations[factor] = min(min_operations[factor], num); + } + } + + // Step 2: 计算答案 + long long result = 0; + for (int i = 1; i <= MAX_VAL; ++i) { + if (min_operations[i] != INT_MAX) { + result = (result + min_operations[i]) % MOD; + } + } + + return result; +} + +int main() { + int n; + cin >> n; + + vector a(n); + for (int i = 0; i < n; ++i) { + cin >> a[i]; + } + + cout << solve(n, a) << endl; + return 0; +} +``` + +### 解释 + +1. **质因数分解**: + - `getPrimeFactors` 函数用于计算一个数的所有质因数。在 C++ 中,我们使用 `sqrt(x)` 来减少不必要的计算。 + +2. **最小操作次数计算**: + - 我们通过一个 `min_operations` 数组来记录每个质因数的最小操作次数。对于每个数,我们找到它的质因数并更新该质因数的最小操作次数。 + +3. **计算子序列最小操作次数之和**: + - 通过 `min_operations` 数组记录的最小操作次数,我们将所有质因数的最小操作次数相加,得到最终结果。 + +4. **优化**: + - 由于题目要求对结果进行 `MOD = 1e9 + 7` 取模,因此在计算最终结果时,使用了 `result = (result + min_operations[i]) % MOD` 来避免结果溢出。 + +### 时间复杂度 + +- **时间复杂度**:主算法的时间复杂度主要是质因数分解部分。对于每个数 $a[i]$,我们需要将其分解成质因数,这需要 $O(\log a[i])$ 的时间。综合考虑所有数的处理,复杂度为 $O(n \log M)$,其中 $M$ 是最大数 $1e6$。 +- **空间复杂度**:需要存储质因数和操作次数,空间复杂度为 $O(M)$,其中 $M = 10^6$。 + +### 总结 + +通过质因数分解、筛法和动态更新的方式,我们能够在 $O(n \log M)$ 的时间复杂度内求解这个问题,并且用取模操作保证结果不会溢出。 + +好的,让我来详细解释如何计算最小操作次数。 + +### 问题核心:如何使得一组数变成相同的数 + +在这个问题中,每个数的最小操作次数是通过选择一个数,并对它进行操作(乘以一个质数或除以它的一个质因数)来使得所有数相同。目标是对于任意给定的一组数,使它们变成相同的数并且操作次数最少。 + +### 如何进行这些操作? + +1. **乘以质数**:你可以选择一个数,将它乘以一个质数。这意味着你可以把该数的质因数增加一个新的质因数。 +2. **除以质因数**:你可以选择一个数,将它除以它的一个质因数(假设它有质因数),这意味着你减少该数的某些质因数。 + +例如,考虑数字 $60$,它的质因数分解为: +$$ +60 = 2^2 \times 3 \times 5 +$$ +你可以通过以下操作来将 $60$ 转变成其他数: +- 除以 $2$:得到 $30$,即 $2^1 \times 3 \times 5$ +- 除以 $3$:得到 $20$,即 $2^2 \times 5$ +- 除以 $5$:得到 $12$,即 $2^2 \times 3$ + +这些操作本质上是通过质因数来改变数字。 + +### 关键思想:将多个数变成相同的数 + +对于数列中的多个数,想要让它们相同,你需要考虑它们的质因数。 + +#### 1. 对每个数进行质因数分解 + +比如,对于数列中的每个数,你可以分解出它们的质因数。例如,对于 $28$,它的质因数分解是: +$$ +28 = 2^2 \times 7 +$$ +对于 $56$,它的质因数分解是: +$$ +56 = 2^3 \times 7 +$$ +这样,我们知道这两个数的质因数是 $2$ 和 $7$,并且它们的幂次分别是不同的。 + +#### 2. 最小操作次数的定义 + +最小操作次数是通过将一个数的质因数变成另外一个数的质因数,或使它们变得一致所需的最少操作次数。 + +举个例子: + +- 对于数 $28 = 2^2 \times 7$ 和 $56 = 2^3 \times 7$,我们可以通过以下步骤将它们变成相同的数: + - $28$ 要增加一个 $2$ (即 $2^2 \times 7$ 变为 $2^3 \times 7$) + - 或者 $56$ 要除以一个 $2$ (即 $2^3 \times 7$ 变为 $2^2 \times 7$) + +这里的操作次数是 1 次(增加或删除一个质因数)。 + +#### 3. 如何计算操作次数? + +对于两个数 $x$ 和 $y$,它们的最小操作次数可以通过比较它们的质因数分解来计算: +- 你需要找到它们质因数分解中的差异部分。 +- 如果一个数的质因数比另一个数多,那么你可以通过除法操作减少它们的质因数。 +- 如果一个数的质因数比另一个数少,那么你可以通过乘法操作增加它们的质因数。 + +### 如何应用到子序列? + +对于每一个子序列,想要让所有数相同,你可以考虑这个子序列中所有数字的最小操作次数之和。这要求我们比较这些数的质因数,找出它们之间的差异,并计算出最小操作次数。 + +#### 4. 筛法和动态计算 + +在我们的算法中,我们使用了一个 `min_operations` 数组来记录每个质因数的最小操作次数。通过这种方式,我们可以避免重复计算每个数字的最小操作次数,而是依赖于之前的计算结果。 + +1. **遍历每个数**,并为它的每个质因数更新 `min_operations` 数组,记录该质因数的最小操作次数。 +2. 最终,我们计算所有质因数的最小操作次数之和,得到答案。 + +### 总结 + +1. 对于每个数,我们分解它的质因数。 +2. 计算使多个数相同所需的最小操作次数是通过比较它们的质因数并计算差异来完成的。 +3. 使用 `min_operations` 数组来跟踪每个质因数的最小操作次数,最终将结果相加。 + +希望这个解释让你对“最小操作次数”的计算过程有了清晰的理解。如果有任何问题,欢迎继续提问! \ No newline at end of file diff --git a/src/test.cpp b/src/test.cpp index 21db87e..b31b92b 100755 --- a/src/test.cpp +++ b/src/test.cpp @@ -1,11 +1,53 @@ +#include +#include +#include +#include #include -#include +#include +#include +#include + +using int64 = int64_t; + +template +void input(Args&&...args){ + (std::cin>>...>>std::forward(args)); +} + +template +std::remove_cvref_t input(){ + std::remove_cvref_t t; + std::cin>>t; + return t; +} + +template +void print(Args&&...args){ + (std::cout<<...<(args)); +} + +constexpr std::array log2 = []()constexpr->std::remove_cvref_t{ + std::remove_cvref_t ret{}; + ret[1] = 0; + for (const auto &i : std::ranges::views::iota((size_t)2, ret.size())) { + ret[i] = ret[i/2] + 1; + } + return ret; +}(); + +int64 lowbit(const int64 &num){ + return num&(-num); +} int main(){ - std::random_device rd; - std::mt19937 rng(rd()); - std::uniform_int_distribution ud(1,10); - for(int i{1};i<=10;i++){ - std::cout<