Codeforces Round #839 (Div. 3) G. Gaining Rating (数学,模拟)

题目链接:https://codeforces.com/contest/1772/problem/G

 

 大致题意:有n名对手,你的初始rating是x,目标是y;

     你打赢对手的时候,rating会加1,输了会减1;

     对于同一个对手,只有你将n名对手打了一遍后,才能再次打他;

     问你,要到达目标,需要打多少次比赛?

 

解题思路: 首先,题目没有限制我们的挑战次序,所以我们可以先把n名对手的rating从小到大排序,

     因为这样子是最优的一种挑战次序;

     然后我们先手动模拟一遍打完n名对手的结果;

     如果结果小于x,那么说明永远不可能到达y,输出-1即可;

     如果在中间就可以到达y,那么直接输出y-x即可;

     然后就是最为普遍的情况,x能升,但是升的不多,没有到达y;

     于是,就需要我们去模拟什么时候可以到达y;

     我们模拟的思路:

     首先,我们能升,说明我们一定可以战胜前z名对手(从小到大排序);

     那么,我们模拟可以战胜第(z+1)名对手的时候,我们的rating是否会大于等于y;

     如果没有,那么我们每遍能升的就会加一;

     如果大于等于了,那么我们就输出结果即可;

时间复杂度:因为我们每次模拟的是第z+1名对手被打败的时候,rating是否大于y了,所以每次都会加一,直到n;

      于是,时间复杂度为O(n);

ac代码:

#include<bits/stdc++.h>
#define int long long

signed main()
{
    std::ios::sync_with_stdio(false); std::cin.tie(0); std::cout.tie(0);

    int T; std::cin >> T;
    while (T--)
    {
        int n, s, e;
        std::cin >> n >> s >> e;
        
        std::vector<int> nums(n + 1, 0);
        for (int i = 1; i <= n; ++i)
            std::cin >> nums[i];
        std::sort(nums.begin() + 1, nums.end());
        int cnt = 0, ans = 0, mid = s, op = 0;
        for (int i = 1; i <= n; ++i)
        {
            if (mid >= nums[i])mid++, op = i;
            else mid--;
        }
        if (s + op >= e) { std::cout << e - s << "\n"; continue; }
        if (mid <= s) { std::cout << "-1\n"; continue; }
        op++;
        while (s < e)
        {
            int MID = op - 1, WID = 2 * MID - n;
            if (op > n) { ans += e - s; break; }
            int up = std::min(e, nums[op]);
            int k = (up - s - MID) / WID;
            ans += k * n; s += WID * k;
            while (s + MID < up)ans += n, s += WID;
            int P = op;
            ans += (up - s); op = (up - s + 1); s = up;
            if (s >= e)break;
            if (s + (P - op + 1) < e)ans += (P - op + 1), s += (P - op + 1), op = P + 1;
            else { ans += (e - s); break; }
            while (op <= n && s < e && s >= nums[op])
                op++, s++, ans++;
            if (s >= e)break;
            ans += n - op + 1; s -= n - op + 1;
        }

        std::cout << ans << "\n";
    }

    return 0;
}

这题其实对于思路来说,确实不是很难,难点在于,模拟的时候,细节有没有考虑清楚,什么时候该改变变量,这些都要考虑好。

如果没有考虑好,可能就会和我一样,wa个20+都有可能(悲

posted @ 2023-02-07 13:47  XiCen  阅读(72)  评论(0)    收藏  举报