补题链接:Here

1538A. Stone Game

数组 Codeforces Round #725 (Div. 3) A~G题解记录 - 图1 的大小为 Codeforces Round #725 (Div. 3) A~G题解记录 - 图2 ,请问每次可以删除最左和最右侧的元素,请问最少执行多少次能删除掉数组中的最大值和最小值 (Codeforces Round #725 (Div. 3) A~G题解记录 - 图3)


在输入的时候确定最大值和最小值的下标,

4种情况

比较从左边删除和右边删除的情况即可

  1. void solve() {
  2. int n; cin >> n;
  3. int id1, id2;
  4. for (int i = 1, x; i <= n; ++i) {
  5. cin >> x;
  6. if (x == 1)id1 = i;
  7. if (x == n)id2 = i;
  8. }
  9. if (id1 > id2) swap(id1, id2);
  10. int cnt1 = (id1 + min(n - id2 + 1, id2 - id1));
  11. int cnt2 = (n - id2 + 1 + min(id1, id2 - id1));
  12. cout << min(cnt1, cnt2) << "\n";
  13. }
  1. void solve() {
  2. int n; cin >> n;
  3. vector<int>a(n);
  4. for (int &x : a)cin >> x;
  5. int maxPos = max_element(a.begin(), a.end()) - a.begin();
  6. int minPos = min_element(a.begin(), a.end()) - a.begin();
  7. cout << min({
  8. max(maxPos, minPos) + 1,
  9. (n - 1) - min(maxPos, minPos) + 1,
  10. (n - 1) - maxPos + minPos + 2,
  11. (n - 1) - minPos + maxPos + 2
  12. }) << "\n";
  13. }

1538B. Friends and Candies

Polycarp 要对他的 Codeforces Round #725 (Div. 3) A~G题解记录 - 图4 个朋友的蛋糕数量重新分配,使得每个人的蛋糕数量相同。

找到最小的 Codeforces Round #725 (Div. 3) A~G题解记录 - 图5 Codeforces Round #725 (Div. 3) A~G题解记录 - 图6 进行分配


数学题,

首先如果总的蛋糕数不是 Codeforces Round #725 (Div. 3) A~G题解记录 - 图7 的倍数,直接输出 Codeforces Round #725 (Div. 3) A~G题解记录 - 图8 ,接下来在统计大于平均值的人数即可

  1. void solve() {
  2. int n; cin >> n;
  3. ll cnt = 0;
  4. vector<int>a(n);
  5. for (int &x : a)cin >> x, cnt += x;
  6. if (cnt % n != 0) {cout << -1 << "\n"; return ;}
  7. int c = 0;
  8. cnt /= n;
  9. for (int i = 0; i < n; ++i) {
  10. if (a[i] > cnt)c++;
  11. }
  12. cout << c << "\n";
  13. }

1538C. Number of Pairs

在数组 Codeforces Round #725 (Div. 3) A~G题解记录 - 图9 中寻找最大对数的 Codeforces Round #725 (Div. 3) A~G题解记录 - 图10%20(1%5Cle%20i%20%3C%20j%20%5Cle%20n)#card=math&code=%28i%2Cj%29%20%281%5Cle%20i%20%3C%20j%20%5Cle%20n%29&id=GIM71) 使得 Codeforces Round #725 (Div. 3) A~G题解记录 - 图11


简单来说要统计两种情况

  • Codeforces Round #725 (Div. 3) A~G题解记录 - 图12
  • Codeforces Round #725 (Div. 3) A~G题解记录 - 图13

二分上面两种情况,然后相减就是合适的区间长度了。

但要注意如果本身 Codeforces Round #725 (Div. 3) A~G题解记录 - 图14 就符合情况的话会重复计算一次,要减去一

最后输出 Codeforces Round #725 (Div. 3) A~G题解记录 - 图15

双指针写法

  1. void solve() {
  2. int n; ll L, R;
  3. cin >> n >> L >> R;
  4. vector<ll>a(n + 1);
  5. for (int i = 1; i <= n; ++i)cin >> a[i];
  6. sort(a.begin() + 1, a.end());
  7. int l = 2, r = n;
  8. ll cnt = 0;
  9. while (l <= n and a[1] + a[1] <= L)l++;
  10. for (int i = 1; i <= n; ++i) {
  11. while (l > 1 and a[l - 1] + a[i] >= L)l--;
  12. while (r > i and a[r] + a[i] > R)r--;
  13. if (r >= max(l, i)) {
  14. if (l > i)cnt += (r - l + 1);
  15. else cnt += r - i;
  16. }
  17. }
  18. cout << cnt << '\n';
  19. }

二分写法

  1. void solve() {
  2. int n, l, r ;
  3. cin >> n >> l >> r;
  4. vector<int>a(n);
  5. for (int &x : a)cin >> x;
  6. sort(a.begin(), a.end());
  7. ll ans = 0;
  8. for (int i = 0; i < n; ++i) {
  9. ans += upper_bound(a.begin(), a.end(), r - a[i]) - a.begin();
  10. ans -= lower_bound(a.begin(), a.end(), l - a[i]) - a.begin();
  11. if (2 * a[i] >= l && a[i] * 2 <= r)ans--;
  12. }
  13. cout << ans / 2 << "\n";
  14. }

1538D. Another Problem About Dividing Numbers

给与 Codeforces Round #725 (Div. 3) A~G题解记录 - 图16Codeforces Round #725 (Div. 3) A~G题解记录 - 图17 两个整数,在一回合操作里,

  • Codeforces Round #725 (Div. 3) A~G题解记录 - 图18Codeforces Round #725 (Div. 3) A~G题解记录 - 图19 两个整数都要找出 Codeforces Round #725 (Div. 3) A~G题解记录 - 图20

请问是否能在 Codeforces Round #725 (Div. 3) A~G题解记录 - 图21 个回合结束后使得 Codeforces Round #725 (Div. 3) A~G题解记录 - 图22


看样例想到是质因数个数的问题,

但试了下先欧拉素数筛晒出 Codeforces Round #725 (Div. 3) A~G题解记录 - 图23 的数据还是 TLE了(常数太大了),然后尝试直接统计因子个数,注意使用 scanf 而不是 cin

  1. void solve() {
  2. int a, b, k;
  3. scanf("%d%d%d", &a, &b, &k);
  4. if (k == 1) {
  5. puts(a != b && (a % b == 0 || b % a == 0) ? "YES" : "NO");
  6. return ;
  7. }
  8. int cnt = 0;
  9. for (int i = 2; i * i <= b; ++i) {
  10. while (b % i == 0) {
  11. b /= i; cnt++;
  12. }
  13. }
  14. if (b != 1)cnt++;
  15. for (int i = 2; i * i <= a; ++i) {
  16. while (a % i == 0) {
  17. a /= i;
  18. cnt++;
  19. }
  20. }
  21. if (a != 1)cnt++;
  22. puts(cnt >= k ? "YES" : "NO");
  23. }

1538E. Funny Substrings

没看懂题意,以后补

1538F. Interesting Function

這道題比賽沒寫出來虧了一個億

给定两个整数 Codeforces Round #725 (Div. 3) A~G题解记录 - 图24Codeforces Round #725 (Div. 3) A~G题解记录 - 图25,其中 Codeforces Round #725 (Div. 3) A~G题解记录 - 图26。 我们将向 Codeforces Round #725 (Div. 3) A~G题解记录 - 图27 加 1,直到结果等于 Codeforces Round #725 (Div. 3) A~G题解记录 - 图28。 因此,将执行 Codeforces Round #725 (Div. 3) A~G题解记录 - 图29 次加法。 对于每个这样的加法,让我们看看在它之后将更改的位数。


累加不同位数的情况下 Codeforces Round #725 (Div. 3) A~G题解记录 - 图30 ,直到 Codeforces Round #725 (Div. 3) A~G题解记录 - 图31Codeforces Round #725 (Div. 3) A~G题解记录 - 图32

  1. void solve() {
  2. ll l, r;
  3. cin >> l >> r;
  4. ll ans = 0;
  5. while (l != 0 || r != 0) {
  6. ans += (r - l);
  7. l /= 10, r /= 10;
  8. }
  9. cout << ans << "\n";
  10. }

如果这算数位DP, 那么算是我见过最简单的数位DP了.

  1. ll dp[20];
  2. void init(int n) {
  3. dp[1] = 1;
  4. for (int i = 2; i <= n; ++i)dp[i] = dp[i - 1] * 10 + 1;
  5. }
  6. int cnt(ll x) {
  7. int a[20] = {0}, Cnt = 0;
  8. while (x) {
  9. a[Cnt++] = x % 10;
  10. x /= 10;
  11. }
  12. ll ans = 0;
  13. for (int i = Cnt - 1; i >= 0; --i)ans += dp[i + 1] * a[i];
  14. return ans;
  15. }
  16. void solve() {
  17. ll l, r;
  18. cin >> l >> r;
  19. cout << cnt(r) - cnt(l) << "\n";
  20. }
  21. int main() {
  22. ios::sync_with_stdio(false), cin.tie(nullptr);
  23. init(15);
  24. int _; for (cin >> _; _--;) solve();
  25. return 0;
  26. }

1538G. Gift Set

Polycarp 有 x 个红色糖果和 y 个蓝色糖果。 使用它们,他想制作礼品套装。 每个礼品套装包含一个红色糖果和 b 个蓝色糖果,或一个蓝色糖果和 b 个红色糖果。 任何糖果最多只能属于一个礼品套装。

帮助 Polycarp 找到他可以创造的最大数量的礼品套装。

例如,如果 Codeforces Round #725 (Div. 3) A~G题解记录 - 图33,那么 Polycarp 可以制作三套礼物:

  • 第一套有 5 个红色糖果和 2 个蓝色糖果;
  • 第二组将有 5 个蓝色糖果和 2 个红色糖果;
  • 第三组将有 5 个蓝色糖果和 2 个红色糖果。

思路来自 Arctic_Clam

考虑二分可分的集合的数量。
如何 Codeforces Round #725 (Div. 3) A~G题解记录 - 图34#card=math&code=O%281%29&id=Qa68x) 求给定的某个集合可行与否?

不妨设 Codeforces Round #725 (Div. 3) A~G题解记录 - 图35

Codeforces Round #725 (Div. 3) A~G题解记录 - 图36 为要验证的集合数量,Codeforces Round #725 (Div. 3) A~G题解记录 - 图37 为第 一种集合数量,Codeforces Round #725 (Div. 3) A~G题解记录 - 图38为 第二种集合数量。
于是我们有

Codeforces Round #725 (Div. 3) A~G题解记录 - 图39

变形可以得到

Codeforces Round #725 (Div. 3) A~G题解记录 - 图40

也就是说,给定n,我们可以求出s的取值区间。再判定下该区间是否合法即可。
Codeforces Round #725 (Div. 3) A~G题解记录 - 图41 Codeforces Round #725 (Div. 3) A~G题解记录 - 图42 取值区间的左界应该是向下取整,但是 Codeforces Round #725 (Div. 3) A~G题解记录 - 图43Codeforces Round #725 (Div. 3) A~G题解记录 - 图44 都是负数,而 C++默认是趋零取整,所以要特判。

  1. ll x, y, a, b;
  2. bool check(ll n) {
  3. ll l = (x - n * b) / (a - b);
  4. if ((x - n * b) < 0 and (-(x - n * b)) % (b - a) != 0)l++;
  5. ll r = (y - n * a) / (b - a);
  6. return l <= r and r >= 0 and l <= n;
  7. }
  8. void solve() {
  9. cin >> x >> y >> a >> b;
  10. if (x > y) swap(x, y);
  11. if (a > b) swap(a, b);
  12. if (a == b) {
  13. cout << (x /= a) << "\n";
  14. return ;
  15. }
  16. ll l = 0, r = x;
  17. while (l < r) {
  18. if (l == r - 1) {
  19. if (check(r)) l = r;
  20. break;
  21. }
  22. ll mid = (l + r) >> 1;
  23. if (check(mid)) l = mid;
  24. else r = mid - 1;
  25. }
  26. cout << l << '\n';
  27. }

似乎本题也可以三分做,dalao也对三分做了正确性证明(tql

二分的正确性是显然的,但是三分的正确性并不那么显然。
为了证明三分的正确性,我们需要证明集合总数n是第一集合数s的函数,且该函数至多有一个峰。
下面给出证明:

Codeforces Round #725 (Div. 3) A~G题解记录 - 图45