P1038 员题 官方题解
Gioush OJ · P1038 员题
员题
【题意简述】
双方各有 匹马,每匹马具有一个速度。两边的马一一比赛,胜、平、负的收益分别为 ,求最大总收益。
【Hint】
【提示】
将双方速度分别排序。若最快马可以获胜,就固定最快马之间的比赛;否则尝试固定最慢马之间的胜局;两种胜局都不存在时,用最慢马消耗对方最快马。
【数据点 1∼21\sim 21∼2】
枚举双方马匹之间的全部双射,再计算每一种安排的收益。时间复杂度为 ,空间复杂度为 。
这个做法的瓶颈在于同时确定了全部配对。如果能证明某一场比赛一定可以出现在最优方案中,就可以逐场固定答案。
【数据点 3∼43\sim 43∼4】
先用插入排序将两组速度升序排列,再执行正解中的两端贪心。时间复杂度为 ,空间复杂度为 。
【正解】
将双方速度序列分别记为 。排序后维护 ,表示双方尚未参赛的最慢马与最快马。
- 若 ,让两匹最快马比赛,答案加一。
- 否则,若 ,让两匹最慢马比赛,答案加一。
- 否则,让 与 比赛。若 ,答案减一;相等时答案不变。
下面分别证明三种选择均不会使答案变劣。
第一种情况中,设某个最优方案让 对阵 ,让 对阵 。交换这两场的对手后, 仍然获胜;又因为 , 对阵 的结果不会比原来更差。因此存在一个最优方案包含最快马之间的配对。
第二种情况中,设某个最优方案让 对阵 ,让 对阵 。交换后 可以战胜 ;又因为 , 对阵 的结果不会比 对阵 更差。因此也存在一个最优方案包含最慢马之间的配对。
最后只剩 且 。此时 无法战胜任何剩余对手, 也不会输给任何剩余的马。设原方案中 对阵 , 对阵 。交换后,若原来两场都失败,收益显然不会低于 ;若恰有一场平局, 对阵更慢的 至少平局,总收益仍不下降;若两场都是平局,则交换后仍为两场平局,或得到一胜一负。因此可以让最慢马消耗对方最快马。
每一步都固定了某个最优方案中的一场比赛,重复这一过程即可得到全局最优解。
【复杂度分析】
排序需要 的时间,四个指针均只会单向移动。总时间复杂度为 ,空间复杂度为 。
【参考代码】
#include <cstdio>#include <algorithm>#define MAXN 1000010using namespace std; int c,n,LineA[MAXN],LineB[MAXN]; int main() {#ifndef ONLINE_JUDGE freopen("race.in","r",stdin); freopen("race.out","w",stdout);#endif scanf("%d",&c); scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&LineB[i]); for (int i=1;i<=n;i++) scanf("%d",&LineA[i]); sort(LineA+1,LineA+n+1); sort(LineB+1,LineB+n+1); int LeftA=1,RightA=n,LeftB=1,RightB=n,Ans=0; while (LeftA<=RightA) { if (LineA[RightA]>LineB[RightB]) { Ans++; RightA--;RightB--; } else if (LineA[LeftA]>LineB[LeftB]) { Ans++; LeftA++;LeftB++; } else { if (LineA[LeftA]<LineB[RightB]) Ans--; LeftA++;RightB--; } } printf("%d\n",Ans); return 0;}