題目大意:初始時有 n 個人,給出一個 n * n 的能力矩陣,如果 maze[ i ][ j ] = 1 的話說明 i 和 j 對戰的話,i 能獲勝,反之亦然,現在 n 個人都在左邊,需要確定一個順序,讓 n 個人依次到達右邊,每過去一個人后,都需要統計此時對于右邊每個人 i 來說,左邊有多少個人能戰勝他,記為 lose[ i ] ,需要確定一個合適的順序,使得?? 的最大值最小
題目分析:又是題意比較難懂的一道題,讀懂題目后,不難看出這是一個有向完全圖,這個題目的順序其實是關鍵,因為順序會影響 lose 求和后的最大值,為了讓這個最大值盡量小,我們首先需要快速計算出這個值,先設 du[ i ] 記為初始時,有多少個人可以擊敗 i ,假設此時左邊還有 a 個人,右邊已經有 b 個人了,設右邊所有人的 du 之和為 sum,此時的 sum = ( ?) + ( 右邊多計算的貢獻 ) ,因為這是一張完全圖,右邊的 b?個人兩兩之間若是對戰的話,肯定會有一個人輸掉,也就是會給 sum 貢獻一個單位,所以多貢獻的答案就是?,考慮完如何計算貢獻后,再考慮一下對于 x 和 y 誰先去右邊更優的問題,假設 du[ x ] > du[ y ] 且 x 和 y 之前的順序都是一樣的,并且之前的入度之和為 sum, 其狀態都為:左邊 a 個人,右邊 b 個人,那么此時:
x先過去,y再過去:和
y先過去,x再過去:和
不難看出后面的一項一樣,因為我們希望最大值最小,也就是希望當 b 較小時,sum 也比越小越好,所以不難得出結論,按照 du[ i ] 升序完成任務的貢獻是最少的
代碼: ?
#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","inline","-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map>
using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=5e3+100;int lose[N];int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);int n;scanf("%d",&n);for(int i=2;i<=n;i++)for(int j=1;j<=i-1;j++){int num;scanf("%1d",&num);if(num==1)lose[j]++;elselose[i]++;}sort(lose+1,lose+1+n);int ans=0,sum=0;for(int i=1;i<=n;i++){sum+=lose[i];ans=max(ans,sum-i*(i-1)/2);}printf("%d\n",ans);return 0;
}