题目描述
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);
// #endifT=1;//scanf("%d",&T);for (;T;--T) solve();return 0;
}