题解 GZOI2024D2B【乒乓球比赛】

4s, 512M

题目描述

Alice 和 Bob 在打乒乓球,乒乓球比赛的规则是这样的:一场比赛中两位选手将进行若干局比赛,选手只需要赢得 X 局比赛就宣告其胜利;每局比赛中两位选手将进行若干盘比赛,选手只需要赢得 Y 盘比赛就宣告其胜利;每盘比赛中两位选手将进行乒乓球对决,有且仅有一位选手能被宣告胜利。

你作为 Alice 的朋友观战了他们的比赛,发现 Alice 赢了 P 盘比赛,Bob 赢了 Q 盘比赛,最后 Alice 取得了整场比赛的胜利。但是你已经忘了 X,Y 的具体取值,请问有多少种 X,Y 使得能存在一种方案满足你记录下的信息。

输入格式

第一行两个正整数 P,Q

输出格式

第一行一个正整数表示方案数。

样例

7 5
4

样例零中,(X,Y) 的所有可能取值为 (1,7),(2,3),(3,2),(7,1)

554 454
1226

数据范围

  • 对于 30% 的数据,P,Q103
  • 对于 50% 的数据,P,Q106
  • 对于 70% 的数据,P,Q1012
  • 另外有 10% 的数据,Q=0
  • 对于 100% 的数据,P,Q1014,并请注意 X,Y 均应为正整数。

solution

设 Bob 赢下了 Z 局比赛,因为 Bob 赢的局数会影响 Alice 可以赢的局数。可以列出以下不等式:

Z<XXYPXY+Z(Y1)ZYQZY+X(Y1)

观察到在 ZYQ 的限制下,将 Z 增大一定是不劣的,所以一定有

Z=min(X1,Q/Y)

因为 XYP,所以可以调和级数枚举 X,Y,获得 50 分。

Z 的取值分类讨论。

Z = floor(Q / Y)

对于 ZYQZY+X(Y1),这自然满足,因为 QZY<Y,所以 QZYY1X(Y1)

对于 XYPXY+Z(Y1)=XY+ZYZ 以及 ZX1 可以写出:

max(Z+1,(P+Z)/YZ)XP/Y

三次整除分块解决。先 Q/Y 确定 Z 以及 Y 对应区间。然后获得 (P+Z)/Y(注意向上取整,或者写为 (P+Z1)/Y+1)以及 P/Y

Z = X - 1

对于 X1<Q/Y (等号在上一种情况讨论了)可以推出 XQ/Y 所以 XYQ

对于 ZYQZY+X(Y1),左边自然满足,右边 Q2XYXY

对于 XYPXY+Z(Y1)=2XYXY+1,其实发现两条不等式很类似。感受一下:

XYP2XYXY+1XYQ2XYXY

两个变量的地位等同,不妨:

Xmin(P,Q)/Y

后面这个部分,P,Q 对称,设 R=max(P1,Q),然后

R2XYXY

X 为主元,求出 X 的范围。

R+Y(2Y1)X

所以

XR+Y2Y1

XR+Y12Y1+1

感受一下,尝试对 Y 进一步整除分块。令 V=R+Y12Y1。求出使得那一坨东西 =VY 的范围。

V(R+Y1)/(2Y1)2VYVR+Y1YR+V12V1YR+V12V1

至此所有问题都解决了。时间复杂度 O(P+Q),具体几倍常数不知道。

code

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define endl "\n"
#define debug(...) void(0)
#endif
using LL = long long;
LL p, q, ret;
int main() {
#ifndef LOCAL
  cin.tie(nullptr)->sync_with_stdio(false);  
#endif
  cin >> p >> q;
  for (LL l = 1, r; l <= p; l = r + 1) {
    LL z = q / l, pz1 = p + z - 1;
    r = p / (p / l);
    if (l <= pz1) r = min(r, pz1 / (pz1 / l));
    if (z) r = min(r, q / z);
    ret += (r - l + 1) * max(0ll, p / l - max(z + 1, pz1 / l + 1 - z) + 1);
  }
  for (LL l = 1, r; l <= min(p, q); l = r + 1) {
    r = min(p, q) / (min(p, q) / l);
    LL v = (max(p - 1, q) + l - 1) / (2 * l - 1);
    if (v) r = min(r, (max(p - 1, q) + v - 1) / (2 * v - 1));
    ret += (r - l + 1) * max(0ll, min(p, q) / l - v);
  }
  cout << ret << endl;
  return 0;
}
posted @   caijianhong  阅读(88)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
历史上的今天:
2023-09-09 题解 SS230909B【下落的小球】
2023-09-09 题解 SS230909A【数据恢复】
点击右上角即可分享
微信分享提示