题目链接:点击查看
题目大意:初始时有 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]++;
else
lose[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;
}