P12711 [KOI 2021 Round 1] 棒球赛季

解题思路

这道题目需要计算在满足特定约束条件下的最大棒球比赛场数。关键点在于理解比赛场数的计算方式和约束条件。

核心思路

  1. 比赛场数计算:

    • 同一地区内比赛:每个地区有M支队伍,每两队之间进行A场比赛

    • 跨地区比赛:不同地区的每两队之间进行B场比赛

    • 约束条件:A = k × B(k为整数且≥1)

  2. 数学建模:

    • 同一地区内比赛总数:N × [M×(M-1)/2] × A

    • 跨地区比赛总数:[N×(N-1)/2] × M² × B

    • 总比赛数 = (N×M×(M-1)/2 × k + N×(N-1)/2 × M²) × B

  3. 二分查找:

    • 在满足总比赛数 ≤ D 的条件下,寻找最大的B值

    • 通过二分查找确定最大的整数B,使得总比赛数不超过D

代码注释

#include<bits/stdc++.h>
#define ll long long  // 定义long long类型别名
using namespace std;
const int N = 2e5 + 10, inf = 0x3f3f3f3f;

void solve()
{
    ll n, m, k, d;
    cin >> n >> m >> k >> d;  // 输入地区数、每地区队伍数、系数k、最大比赛数D
    
    // 计算系数t1:同一地区内比赛的系数部分
    ll t1 = n * m * (m - 1) / 2 * k;
    // 计算系数t2:跨地区比赛的系数部分  
    ll t2 = n * (n - 1) / 2 * m * m;
    
    ll ans = -1;  // 初始化答案为-1(表示无解)
    ll l = 1, r = 1e9;  // 二分查找的左右边界,B的取值范围[1, 10^9]
    
    // 二分查找寻找最大的B值
    while(l <= r)
    {
        ll mid = l + r >> 1;  // 取中间值
        // 检查当前B=mid时总比赛数是否不超过D
        if((t1 + t2) * mid <= d){
            l = mid + 1;      // 满足条件,尝试更大的B值
            ans = mid;        // 更新当前找到的最大有效B值
        }
        else r = mid - 1;     // 不满足条件,尝试更小的B值
    }
    
    if(ans == -1) cout << -1 << endl;  // 没有找到合适的B值
    else cout << (t1 + t2) * ans << endl;  // 输出最大总比赛数
}

int main()
{
    int t; cin >> t;  // 输入测试用例数量
    while(t--)
    {
        solve();  // 处理每个测试用例
    }
    return 0;
}

// 注释说明:
// bd = n * m * (m - 1) / 2 * a;          // 同一地区内比赛总数
// wd = n * (n - 1) / 2 * m * m * b;      // 跨地区比赛总数
// a = k * b;                              // 约束条件
// wd + bd <= d                            // 总比赛数约束

// 代入约束条件后:
// bd = n * m * (m - 1) / 2 * k * b;
// wd = n * (n - 1) / 2 * m * m * b;
// bd + wd = n * m * (m - 1) / 2 * k * b + n * (n - 1) / 2 * m * m * b <= d

// 提取公因式:
// t1 = n * m * (m - 1) / 2 * k           // 同一地区比赛系数
// t2 = n * (n - 1) / 2 * m * m           // 跨地区比赛系数
// bd + wd = (t1 + t2) * b <= d           // 总比赛数表达式

 公式代码

#include<bits/stdc++.h>
#define ll long long  // 定义long long类型别名,防止整数溢出
using namespace std;
const int N = 2e5 + 10, inf = 0x3f3f3f3f;

void solve()
{
    ll n, m, k, d;
    cin >> n >> m >> k >> d;  // 输入:地区数、每队队伍数、系数k、最大比赛数
    
    // 计算系数t1:同一地区内比赛的系数
    // n个地区 × 每个地区m支队伍 × 每队与其他(m-1)队比赛 × 系数k
    ll t1 = n * m * (m - 1) / 2 * k;
    
    // 计算系数t2:跨地区比赛的系数  
    // n个地区中选2个的组合数 × 每个地区m支队伍 × 另一地区m支队伍
    ll t2 = n * (n - 1) / 2 * m * m;
    
    // 计算最大可能的B值:D除以总系数
    ll ans = d / (t1 + t2);
    
    // 计算对应的总比赛数
    ans = (t1 + t2) * ans;
    
    // 输出结果:如果结果为0说明无解,否则输出最大比赛数
    if(ans == 0) cout << -1 << endl;
    else cout << ans << endl;
}

int main()
{
    int t; cin >> t;  // 输入测试用例数量
    while(t--)
    {
        solve();  // 处理每个测试用例
    }
    return 0;
}

// 公式推导注释:
// bd = n * m * (m - 1) / 2 * a;          // 同一地区内比赛总数
// wd = n * (n - 1) / 2 * m * m * b;      // 跨地区比赛总数
// a = k * b;                              // 题目约束条件
// wd + bd <= d                            // 总比赛数限制

// 代入约束条件:
// bd = n * m * (m - 1) / 2 * k * b;      // 将a=k*b代入
// wd = n * (n - 1) / 2 * m * m * b;      // 保持不变
// bd + wd = (n*m*(m-1)/2*k + n*(n-1)/2*m²) * b <= d

// 提取公因式:
// t1 = n * m * (m - 1) / 2 * k           // 同一地区比赛系数
// t2 = n * (n - 1) / 2 * m * m           // 跨地区比赛系数
// 总比赛数 = (t1 + t2) * b ≤ d           // 简化后的表达式

 

posted @ 2025-08-29 13:22  CRt0729  阅读(5)  评论(0)    收藏  举报