Codeforces Round #839 (Div. 3)

20 篇文章 1 订阅
4 篇文章 0 订阅

Problem - G - Codeforces

        (1)题目大意

                一个人想提升下棋的rating,但是他只能一轮一轮来,若是他大于或者等于对战的那个人的rating,他的rating就会加1,那个对战的人rating不变,若是他的rating小于对战的那个人的rating,他的rating就会减1,问你他的rating能否有可能从x变成y,如果有输出最小对战次数,否则输出0.

         (2)解题思路

                考虑二分答案,二分k轮,对于k轮我们算一下可以产生多少rating,以及下一轮最大可以有多少rating,我们从小到大去打对手,若是不敌,我们考虑能否在k轮内使得能打过,然后下一次 每轮最大获得rating可以增加2了,最后给每一个ans取个min即可。

        (3)代码实现

// Problem: G. Gaining Rating
// Contest: Codeforces - Codeforces Round #839 (Div. 3)
// URL: https://codeforces.com/contest/1772/problem/G
#include "bits/stdc++.h"
#define rep(i, z, n) for (int i = z; i <= n; i++)
#define per(i, n, z) for (int i = n; i >= z; i--)
#define ll long long
#define PLL pair<long long, long long>
#define db double
#define PII pair<int, int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const int N = 2e5 + 10;
ll a[N];
ll n, now, fur, mius;
PLL check(ll k)
{
    //打k轮能获得多少rating
    ll tmp = now, minnus = mius;
    vector<ll> need;
    ll tmpk = k, pt = 0;
    rep(i, 1, n)
    {
        if (tmp >= a[i])
        {
            tmp += 1;
            pt++;
            need.push_back(0);
        }
        else
        {
            ll cnt = (a[i] - tmp + minnus - 1) / minnus;
            if (cnt > tmpk)
            {
                continue;
            }
            tmp += cnt * minnus + 1;
            pt++;
            minnus += 2;
            tmpk -= cnt;
            need.push_back(cnt);
            int j = i + 1;
            while (j <= n && a[j] <= tmp)
            {
                pt++;
                tmp++;
                need.push_back(0);
                minnus += 2;
                j++;
            }
            i = j - 1;
        }
    }
    ll have = 0, pre = 0, cnt = 0;
    for (auto x : need)
    {
        pre += x;
        have += (k - (pre)) - (pre);
        cnt++;
    }
    have -= 1LL * (n - cnt) * k;
    return {have, pt};
}
void solve()
{
    cin >> n >> now >> fur;
    rep(i, 1, n)
    {
        cin >> a[i];
    }
    sort(a + 1, a + 1 + n);
    mius = 0;
    ll tmp = now, mx = 0;
    rep(i, 1, n)
    {
        if (tmp >= a[i])
        {
            tmp++;
            mius++;
        }
        else
        {
            tmp--;
            mius--;
        }
        if (tmp == fur)
        {
            cout << i << endl;
            return;
        }
        mx = max(mx, mius);
    }
    if (mius <= 0)
    {
        cout << -1 << endl;
        return;
    }
    //每大场净胜minus点rating,mx单场最多拿多少rating
    ll dis = fur - now, l = 1, r = 1e12, ans = 1e18;
    while (l <= r)
    {
        ll mid = (l + r) >> 1;
        PLL nw = check(mid);
        // cout << mid << ',' << nw.fi << ',' << nw.se << endl;
        if (nw.fi + nw.se >= dis)
        {
            r = mid - 1;
            ans = min(ans, max(0LL, dis - nw.fi) + mid * n);
        }
        else
        {
            l = mid + 1;
        }
    }
    cout << ans << endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int T = 1;
    cin >> T;
    while (T--)
        solve();
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值