✅ 题目要求简述:
给定整数 n, k, x
,请你找一个区间 [l, r]
满足:
- 区间长度为
k
,即r = l + k - 1
- 区间中恰好有
n
个x
的倍数 1 ≤ l ≤ r < 2e9
- 如果不存在这样的区间,输出
-1
✅ 解题思路:
- 直观理解:一个区间中 x 的倍数是规则出现的。如果我们在区间 [l, r] 中想要恰好有 n 个 x 的倍数,那么最紧凑的情况是: l 为最小的 x 的倍数(比如 x)r 为第 n 个 x 的倍数(即 n * x)此时区间长度最小:k = r - l + 1 = (n * x) - x + 1 = (n - 1) * x + 1最稀疏的情况:两个 x 的倍数之间尽量拉远,但不能超过 k 的限制。
- 最小 / 最大可能长度推导:最小长度:连续 n 个 x 的倍数,最紧凑,即:最大长度:在区间内可以包含最多 n 个 x 的倍数,如果它们正好出现在两端(最稀疏),间距最小是:如果题目给的 k 不在 [minLen, maxLen] 之间,说明没办法构造这样的区间,直接输出 -1。
- 构造合法区间 [left, right]:从最紧凑的区间开始:当前区间长度为:right - left + 1如果小于 k,我们在保持区间内倍数数量不变的前提下,“对称”地扩展: left-- & right++每次扩展会让区间长度 +2,直到长度为 k
✅ 你写的代码 + 详细注释:
#include<iostream> #include<algorithm> #include<cmath> #include<vector> #define int long long // 使用 long long 防止大数溢出 using namespace std; // 解题函数 void solve(){ int n, k, x; // 输入:n 表示希望区间内有 n 个 x 的倍数 // k 表示区间长度 // x 是倍数目标 cin >> n >> k >> x; // 最小长度:连续 n 个 x 的倍数所构成的最短区间长度 int minLen = (n - 1) * x + 1; // 最大长度:还能容纳 n 个倍数的最大区间长度(再长,倍数数目可能会减少) int maxLen = (n + 1) * x - 1; // 判断是否存在合法的区间长度 if (k < minLen || k > maxLen) { cout << "-1"; // 不存在这样的区间 return; } // 起始区间:最紧凑的区间,左端点为第一个倍数,右端点为第 n 个倍数 int left = x; int right = n * x; // 当前区间长度为:right - left + 1,我们要调整使它恰好为 k k = k - (right - left + 1); // 还需要扩展的长度 // 从两边对称扩展,每次扩展两端各1个数,直到区间长度满足要求 while (k) { if (k) { left--; // 左端点向左扩展 k--; } if (k) { right++; // 右端点向右扩展 k--; } } // 输出最终区间 [left, right] cout << left << " " << right << "\n"; } // 主函数 signed main(){ int T = 1; // 默认只做一组输入 ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); // 提高读写效率 // cin >> T; // 如果是多组输入可以打开这一行 while (T--) { solve(); } return 0; }
✅ 样例验证:
输入:
2 881761968 737875443
输出:
737875443 1619637410 ✅
✅ 总结优势:
- 💡 无需二分,逻辑清晰直接
- 🧠 用等差间隔的思维直接构造合法区间
- 🪄 区间平移对称调整,优雅又精巧