LOJ #2155. 「POI2011 R1」同谋者 Conspiracy(深入性质分析)

题目

性质一:
两个合法方案中,在一个方案 A A 是后勤组且在另一个方案 B B 中不是的人最多有一个,同谋者同理。
证明:反证,如果有两个,那么在 A A 中同为后勤组保证他们间有边,与他们在 B B 中同为同谋者矛盾。
那么拿到这个性质就可以按照网上的大多数题解直接 2 s a t 2-sat 一波找出特解然后一个人一个人的尝试切换组之类的就可以了。

但是我们初步算一下,这个题没给边数的范围,所以我们是可能 M L E MLE 的(算一下最大边数可以得出大概 280 M B 280MB 这个数字)。
但是他们过了。也许他们用了什么奇技淫巧

性质二:
所有合法方案中不存在两个人 A , B A,B , A A 的认识人数: d a da > > B B 的认识人数: d b db 并且 A A 为同谋者, B B 为后勤组。
证明:(这个命题给出的形式都暗示这应该是个反证)如果存在,设后勤组人数为 S S ,则有 d b > = S 1 db>=S-1 (后勤组间都有边), d a > d b da>db (由假设), d a < = S da<=S (a的所有边只能连向后勤组)。那么我们可以得到 d b = S 1 , d a = S db=S-1,da=S ,哪里有矛盾呢? d a = S da=S 表示 a a 也要往 b b 连边,所以 d b = S = d a db = S = da ,矛盾。
有了这个性质,我们就可以只需要点的度数,将其从大到小排序,依次加入后勤组,再简单的利用后勤组每个点的度数和=后勤组完全图中的边数+图中所有的边数,这个等式成立时即保证了这可以形成一个合法的方案(证明可以考虑这个题没有重边)。
扫一遍组合数计算度数相等的方案即可。

结合性质一和性质二:
可以得到我们第一次合法时,剩下的(可以构成度数相等的点只有一个)或者是(只能选一个),因为其他情况时可以构造出违背性质一的方案,所以可以简单写成下面这个简单的代码而省去组合数。

A C   C o d e \mathrm{AC \ Code}

#include<bits/stdc++.h>
#define maxn 5005
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
using namespace std;

char cb[1<<18],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<18,stdin),cs==ct)?0:*cs++)
void read(int &res){
	char ch;
	for(;!isdigit(ch=getc()););
	for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
}
int n,m,s,a[maxn],cnt[maxn],c2[maxn];

int main(){
	read(n);
	rep(i,1,n){
		read(a[i]),cnt[a[i]]++,m+=a[i];
		rep(j,1,a[i]) read(cnt[maxn-1]);
	}
	m>>=1;
	sort(a+1,a+1+n);
	per(i,n,1){
		s+=a[i];cnt[a[i]]--,c2[a[i]]++;
		if((n-i+1)*(n-i)/2+m==s){
			printf("%d",cnt[n-i+1]+cnt[a[i]]*c2[a[i]]-(n*(n-1)/2==m)+1);
			return 0;
		} 
	}
	putchar('0');
}

发布了627 篇原创文章 · 获赞 91 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/103704679