一道练手的题,思路很快就能出来,练习简化的用语言去实现
题目链接
题目大意
两个人比赛,现在已经进行了 n n n轮,给定两行、每行 n n n个正整数作为每轮的分数,每人总分计算方法为,得分从大到小排前 n / 4 n/4 n/4个的和,接下来每轮每人可能得分为 x ( 0 < = x < = 100 ) x(0<=x<=100) x(0<=x<=100),问最小多少轮后第一个人分数高于第二个人
思路
很容易想到用先排序再前缀和处理一下得分
如果第一个人总分小于第二个人
再思考如何分配后面的轮次
显然最差情况是再来 n n n轮,结果完全反过来,使得两人分数相等
思考发现,最优情况是,每轮让第一个人 + 100 +100 +100,第二个人 + 0 +0 +0
所以方法出来了,循环实现上述语句
发现直接模拟的话实现很麻烦,而且可能会 T T T掉
所以考虑每轮分数之间的关系
考虑第一个人,每次加 100 100 100分都会再减去被选中的分数中的最小值,所以总共第 k k k轮(补加的第 i i i轮)后第一个人的有效分数段数为 n = k − k / 4 n=k-k/4 n=k−k/4,分数为 i ∗ 100 + p r e a [ n − i ] i*100+prea[n-i] i∗100+prea[n−i]
考虑第二个人,每次是加 0 0 0分,显然如果还有没有加上的分数会优先被加入总分,
当轮数大于有效分数的数量时,总分保持不变
ACcode
#include<bits/stdc++.h>using namespace std;using ll = long long;bool cmp(int x, int y) {return x > y;
}void solve()
{int n;cin >> n;vector<int>a(n + 3), b(n + 3);for (int i = 1;i <= n;i++)cin >> a[i];for (int i = 1;i <= n;i++)cin >> b[i];vector<ll>pa(n + 3), pb(n + 3);sort(a.begin() + 1, a.begin() + 1 + n, cmp);sort(b.begin() + 1, b.begin() + 1 + n, cmp);pa[0] = 0;pb[0] = 0;for (int i = 1;i <= n;i++)pa[i] = pa[i - 1] + a[i];for (int i = 1;i <= n;i++)pb[i] = pb[i - 1] + b[i];int ans = 0;for (;;ans++) {int k = n + ans;int d = k - k / 4;ll suma = 100 * ans + pa[d - ans];ll sumb = d < n ? pb[d] : pb[n];if (suma >= sumb) {cout << ans << '\n';return;}}
}int main()
{ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int t;cin >> t;while (t--) {solve();}return 0;
}