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+都有可能(悲

浙公网安备 33010602011771号