CF730E. Award Ceremony
- problem
- solution
- code
problem
题目链接
题目大意:
给出 nnn 个队封榜时的榜单 aia_iai 和揭榜时的变化情况 did_idi。
揭榜时,这个队的名次会变化 tit_iti。
注意在别的队揭榜时,自己队的排名也是动态变化的。
计算的变化名次是自己揭榜前后的名次差,而非最终排名与最初排名差。
然后问如何安排揭榜顺序,使得 sum(∣ti∣)sum(|t_i|)sum(∣ti∣) 最大。
1≤n≤100,1≤ai≤100,−100≤di≤1001≤n≤100,1≤ai≤100, -100≤di≤1001≤n≤100,1≤ai≤100,−100≤di≤100。
solution
考虑两两队伍之间的排名变化贡献。
-
如果两个队伍揭榜前后相对排名顺序发生变化,则无论怎么安排两个队伍的揭榜先后,答案贡献都是 111。
i.e.
假设 iii 排名在 jjj 前面(i<ji<ji<j),揭榜后 jjj 排名更靠前 i>ji>ji>j。有两种情况。
- iii 分数下降,jjj 可能上升也可能下降,但 iii 一定下降地更猛。
- 假设先揭榜 iii ,则 iii 排名变成 jjj 后面,贡献为 111,后面揭榜 jjj,依旧在 iii 之前。
- 假设先揭榜 jjj,则 jjj 可能已经超过 iii ,后面揭榜仍在 iii 前面;也可能还是没有超过 iii,但是 iii 揭榜后就掉在 jjj 后面了。
- iii 分数上升,jjj 必须上升,且 jjj 一定上升地更猛。假设揭榜过程与上面一样。不再赘述。
- iii 分数下降,jjj 可能上升也可能下降,但 iii 一定下降地更猛。
-
如果两个队伍揭榜前后相对顺序并未发生改变。则有两种情况。
- 不管先揭榜谁,都保持着 i<ji<ji<j。则对答案无贡献。
- iii 被 jjj 超过后又再次超过了 jjj。答案就是 222。
按照上述方法会得到一个有向无环图,根据拓扑排序就能得到揭晓的顺序,但是本题并未做要求。
只要最终改变的最大值结果,那么就直接枚举两个队伍,看属于上面的哪种情况贡献。计算即可。
时间复杂度为 O(n2)O(n^2)O(n2)。
证明这样的做法得到的关系图不存在环。
只有第二种情况的第二点,贡献为 222,这种
case
会需要考虑两个队伍揭榜的先后顺序。即只有这种
case
才会在图上增加一条边,因此环只可能在这个地方产生。假设三个队伍 i,j,ki,j,ki,j,k 构成环。
首先因为两个队伍之间有边,所以有 iii 揭榜后能超过 jjj ,然后又被 jjj 揭榜后反超,这样贡献才为 222。
(j,k),(k,i)(j,k),(k,i)(j,k),(k,i) 同样也是如此。
即 jjj 揭榜后超过 kkk 又被 kkk 反超,kkk 揭榜后超过 iii 又被 iii 反超。
这三个揭榜顺序必然是确定的,所以名次改变方向是固定的。
由 (i,j)(j,k)(i,j)(j,k)(i,j)(j,k) 之间的关系就知道 kkk 揭榜后超过 i,ji,ji,j 不可能又让 iii 再揭榜一次反超。
所以这个情况必然是如图所示:
code
#include <bits/stdc++.h>
using namespace std;
#define maxn 105
struct node { int val, id, tag;bool operator < ( node &t ) {return val == t.val ? id < t.id : val > t.val;}
}a[maxn];
int n, ans;int calc( int x, int y ) {node lst_x = a[x], lst_y = a[y];node new_x = lst_x, new_y = lst_y;new_x.val += lst_x.tag;new_y.val += lst_y.tag;if( lst_x < lst_y and new_y < new_x ) return 1;if( lst_y < lst_x and new_x < new_y ) return 1;if( lst_x < lst_y and new_x < new_y and new_y < lst_x ) return 2;if( lst_x < lst_y and new_x < new_y and lst_y < new_x ) return 2;if( lst_y < lst_x and new_y < new_x and new_x < lst_y ) return 2;if( lst_y < lst_x and new_y < new_x and lst_x < new_y ) return 2;return 0;
}int main() {scanf( "%d", &n );for( int i = 1;i <= n;i ++ ) scanf( "%d %d", &a[i].val, &a[i].tag ), a[i].id = i;sort( a + 1, a + n + 1 );for( int i = 1;i <= n;i ++ )for( int j = i + 1;j <= n;j ++ )ans += calc( i, j );printf( "%d\n", ans );return 0;
}