cunzai_zsy0531

关注我

CF1400G Mercenaries 题解

如果没有敌对关系,枚举一共选 \(i\) 个人,如果有 \(j\) 个人满足 \(i\in [l_j,r_j]\),那么方案数是 \(\binom{i}{j}\)

接下来考虑限制,由于 \(m\leq 20\),考虑容斥,直接钦定一个集合 \(S\),其中所有为 \(1\) 的位置对应的限制必选,这个方案数也是一个组合数。由于钦定选定的位置最多也就 \(2m\),直接把这些答案都预处理一遍就行了。

点击查看代码
const int N=3e5+13,M=20+13;
struct Node{int l,r;}a[N];
struct edge{int u,v;}E[M];
int n,m,b[N],mul[N],invmul[N],sum[M<<1][N];
bool vis[N];
inline void init(){
	mul[0]=invmul[0]=1;
	for(int i=1;i<=n;++i) mul[i]=(ll)mul[i-1]*i%mod;
	invmul[n]=invv(mul[n]);
	for(int i=n-1;i;--i) invmul[i]=(ll)invmul[i+1]*(i+1)%mod;
}
inline int C(int n,int m){if(n<0||m<0)return 0;return (ll)mul[n]*invmul[m]%mod*invmul[n-m]%mod;}
int main(){
	read(n),read(m);
	init();
	for(int i=1;i<=n;++i){
		read(a[i].l),read(a[i].r);
		b[a[i].l]++,b[a[i].r+1]--;
	}
	for(int i=0;i<m;++i) read(E[i].u),read(E[i].v);
	for(int i=1;i<=n;++i) b[i]+=b[i-1];
	for(int j=0;j<=2*m;++j)
		for(int i=1;i<=n;++i) sum[j][i]=(sum[j][i-1]+C(b[i]-j,i-j))%mod;
	int ans=0;
	for(int s=0;s<(1<<m);++s){
		int l=1,r=n,pcnt=0;
		for(int i=0;i<m;++i){
			if(!((s>>i)&1)) continue;
			int u=E[i].u,v=E[i].v;
			if(!vis[u]) ++pcnt,vis[u]=1,l=max(l,a[u].l),r=min(r,a[u].r);
			if(!vis[v]) ++pcnt,vis[v]=1,l=max(l,a[v].l),r=min(r,a[v].r);
			if(l>r) break;
		}
		int tp=(popcount(s)&1?-1:1);
		if(l<=r) ans+=tp*((sum[pcnt][r]-sum[pcnt][l-1]+mod)%mod),ans=(ans%mod+mod)%mod;
		for(int i=0;i<m;++i){
			if(!((s>>i)&1)) continue;
			int u=E[i].u,v=E[i].v;vis[u]=vis[v]=0;
		}
	}
	println(ans);
	return 0;
}
posted @ 2022-05-28 15:22  cunzai_zsy0531  阅读(28)  评论(0编辑  收藏  举报