2021 Hubei Provincial Collegiate Programming Contest E. Revue

题目描述

n个人,每个人的初始分数不同(具体分数未知)

有m次已知的Revue(按顺序发生),每次Revue形式为(x,y),意为x打败y,之后x的分变成二者max,y变成min

现在你要按顺序在最后加入w次Revue,要保证 在所有m+w次Revue中删掉任意k(k给出)次Revue后 的 所有初始分数的可能中,1都能获得最大分值

最小化w,当w<=1000时输出方案

n,m,k<=1e6

题解

顶级思维题

实际不需要关心其他的分数,只要考虑max最后能否到1上就行

问题等价于:两个人博弈,人A加入w次操作,之后另一个人B确定max位置,同时尽可能删操作使max到不了1
(你只能决定加操作,max位置、删哪些都决定不了,所以不妨设另一个人B来按最优方式干扰你)

假设max位置在x,B删f[x]次操作就可以阻止max到A,当f[x]<=K时你只要加入K+1-f[x]个(1,x)的Revue就可以使max在x时合法,对每个x加边即可保证所有情况合法

现在问题变成了求f[x],修正/严谨一下f[x]的定义,f[x]表示在当前的Revue序列下,要让max最终留在x的最小删次数(这里的最小是所有初始max位置情况的最小)

那么f[x]初始为0(max就在x),之后每加入一个Revue(x,y)时,对于x来说,多了用f[y]次操作让max留在y,然后利用最后/新加的Revue(x,y)把max移到x,所以f[x]←max(f[x],f[y]);
同时,y如果要把max留在y,那么多了这个Revue(x,y)必删,所以f[y]←f[y]+1

然后做完了,f[x]求出后直接构造就行,还是当f[x]<=K时加K+1-f[x]次Revue
这样当B想初始把max放到合适位置,然后删f[x]次操作后到x时,要额外多删K+1-f[x]次;做不到,所以合法

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (int a=b; a<=c; a++)
#define fd(a,b,c) for (int a=b; a>=c; a--)
#define ll long long
//#define file
using namespace std;

const int N=1e6+10;
int n,m,K,T;
int f[N];

char ch;
int Read()
{
	int x=0;
	ch=getchar();
	while (!(ch>='0' && ch<='9')) ch=getchar();
	while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
	return x;
}

void solve()
{
	n=Read(),m=Read(),K=Read();
    fo(i,1,m)
    {
    	int x,y;
    	x=Read(),y=Read();
		f[x]=min(f[x],f[y]);
		++f[y];
	}
	
	ll w=0;
	fo(i,2,n) if (f[i]<=K) w+=K+1-f[i];
	
	printf("%lld\n",w);
	if (w<=1000)
	{
		fo(i,2,n)
		if (f[i]<=K)
		{
			fo(j,1,K+1-f[i])
			printf("%d %d\n",1,i);
		}
	}
}

int main()
{
//	freopen("E.in","r",stdin);
//	#ifdef file
//	freopen("a.out","w",stdout);
//	#endif

    T=1;
    //scanf("%d",&T);
    for (;T;--T) solve();

    return 0;
}
posted @ 2024-11-16 22:45  gmh77  阅读(4)  评论(0编辑  收藏  举报