題目鏈接:點擊這裏
題意:給出一個封榜時的榜單,按照封榜時的分數排序,每個隊伍在封榜後分數會改變,名次也會對應的變化t名。現在要求一個揭曉的順序最大化
對於兩個隊伍i,j,考慮揭曉他們的相對順序。如果這兩個隊在揭曉前和揭曉後相對排名不同,那麼說明無論先揭曉哪個隊伍,最後對答案的貢獻總是1(畫個圖很容易看出來)。如果兩個隊揭曉前後相對排名不變,就分兩種情況考慮:
1. 無論先後揭曉順序如何,都不會使得一個隊伍越過另一個隊伍,這樣的情況下顯然先後順序無所謂,對答案的貢獻都是0;
2. 假設先揭曉i以後i的排名變化能夠越過j,然後再揭曉j以後j的排名又會重新越過i,那麼揭曉的順序就先i後j,對答案的貢獻是2,同理的情況亦然。
按照上述的方法,必然能夠得到一個拓撲網絡,然後按照拓撲關係即可得到一個揭曉的先後序列(當然題目沒有要求,只要確定最大值即可)。
現在來證明這樣的做法得到的關係圖沒有環:
因爲只有第二種情況的第二點纔會給關係圖增加一條邊,所以環只會在這裏產生。假設有三個隊伍i,j,k構成一個環,那麼i揭曉後越過j,j揭曉後又重新越過i,jk和ki同理。顯然這種情況不存在,因爲ijk的相對次序必然是確定的,揭曉後的名次改變方向也必須一致,那麼(i改變後越過j),(j改變後越過k)與(k改變後越過i相矛盾),如圖:
於是不存在環關係,證畢。
#include <bits/stdc++.h>
using namespace std;
#define maxn 105
struct node {
int num, id, add;
bool operator < (const node &a) const {
return num > a.num || (num == a.num && id < a.id);
}
}a[maxn];
int pre[maxn];
int n;
int ok (int i, int j) {
node x = a[i], y = a[j], xx = x, yy = y;
xx.num = x.num+x.add, yy.num = y.num+y.add;
if (x < y && yy < xx) return 1;
if (y < x && xx < yy) return 1;
if (x < y && y < xx && xx < yy) return 2;
if (y < x && x < yy && yy < xx) return 2;
if (x < y && yy < x && xx < yy) return 2;
if (y < x && xx < y && yy < xx) return 2;
return 0;
}
int main () {
//freopen ("more.in", "r", stdin);
int ans = 0;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i].num >> a[i].add;
a[i].id = i;
}
sort (a+1, a+1+n);
for (int i = 1; i <= n; i++) {
for (int j = i+1; j <= n; j++) {
ans += ok (i, j);
}
}
cout << ans << endl;
return 0;
}