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;
}