中石油训练赛 - Incremental Induction(贪心)

题目链接:点击查看

题目大意:初始时有 n 个人,给出一个 n * n 的能力矩阵,如果 maze[ i ][ j ] = 1 的话说明 i 和 j 对战的话,i 能获胜,反之亦然,现在 n 个人都在左边,需要确定一个顺序,让 n 个人依次到达右边,每过去一个人后,都需要统计此时对于右边每个人 i 来说,左边有多少个人能战胜他,记为 lose[ i ] ,需要确定一个合适的顺序,使得 \sum lose[i]  的最大值最小

题目分析:又是题意比较难懂的一道题,读懂题目后,不难看出这是一个有向完全图,这个题目的顺序其实是关键,因为顺序会影响 lose 求和后的最大值,为了让这个最大值尽量小,我们首先需要快速计算出这个值,先设 du[ i ] 记为初始时,有多少个人可以击败 i ,假设此时左边还有 a 个人,右边已经有 b 个人了,设右边所有人的 du 之和为 sum,此时的 sum = ( \sum lose[i] ) + ( 右边多计算的贡献 ) ,因为这是一张完全图,右边的 b 个人两两之间若是对战的话,肯定会有一个人输掉,也就是会给 sum 贡献一个单位,所以多贡献的答案就是 C_{b}^{2}=\frac{b*(b-1)}{2},考虑完如何计算贡献后,再考虑一下对于 x 和 y 谁先去右边更优的问题,假设 du[ x ] > du[ y ] 且 x 和 y 之前的顺序都是一样的,并且之前的入度之和为 sum, 其状态都为:左边 a 个人,右边 b 个人,那么此时:

  1. x先过去,y再过去:sum+du[x]-\frac{b*(b-1)}{2}sum+du[x]+du[y]-\frac{b*(b+1)}{2}
  2. y先过去,x再过去:sum+du[y]-\frac{b*(b-1)}{2}sum+du[x]+du[y]-\frac{b*(b+1)}{2}

不难看出后面的一项一样,因为我们希望最大值最小,也就是希望当 b 较小时,sum 也比越小越好,所以不难得出结论,按照 du[ i ] 升序完成任务的贡献时最少的

代码:
 

#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","inline","-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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;
}

 

你可能感兴趣的:(贪心)