题意:
现在有n个人,让你组一支队伍,并且每个人都有限制,如果你选择这个人,那么组队人数必须在li~ri之间。并且有m条限制,表示一对人不能同时选择。
问你最终有多少种选择方法。
题解:
正难则反
我们考虑当前已经确定了有k个人要选,
那么对于m个限制中的第i个,如果k在l~r中,也就是可以选的情况有
C
n
u
m
[
k
]
−
2
k
−
2
C_{num[k]-2}^{k-2}
Cnum[k]−2k−2
num[i] 表示选i个人有多少的人符合这条限制
明显这样子去做会有重复的情况,那么我们需要考虑容斥,也就是枚举m的所有状态,然后加上影响。
假设现在我们有add条限制,涉及tot个人当前限制可以取的人数区间为l~r,那么这个限制的影响就是
∑
i
=
l
r
C
n
u
m
[
i
]
−
t
o
t
i
−
t
o
t
∗
(
a
d
d
%
2
?
−
1
:
1
)
\sum\limits_{i=l}^{r}C_{num[i]-tot}^{i-tot}*(add\%2?-1:1)
i=l∑rCnum[i]−toti−tot∗(add%2?−1:1)
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5,M=45;
#define ll long long
const ll mod=998244353;
ll fac[N],inv[N],sum[M][N];
struct node{
int l,r;
}p[N],lim[M];
int num[N],vis[N];
ll qpow(ll a,ll b){ll ans=1;for(;b;b>>=1,a=a*a%mod)if(b&1)ans=ans*a%mod;return ans;}
ll C(int n,int m){
if(n<m||m<0)return 0;
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main()
{
fac[0]=inv[0]=1;
for(int i=1;i<N;i++)fac[i]=fac[i-1]*i%mod;
inv[N-1]=qpow(fac[N-1],mod-2);
for(int i=N-2;~i;i--)
inv[i]=inv[i+1]*(i+1)%mod;
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d%d",&p[i].l,&p[i].r),num[p[i].l]++,num[p[i].r+1]--;
for(int i=1;i<=n;i++)
num[i]+=num[i-1];
for(int i=0;i<m;i++)
scanf("%d%d",&lim[i].l,&lim[i].r);
ll ans=0;
for(int i=1;i<=n;i++)
if(i<=num[i])
ans=(ans+C(num[i],i))%mod;
for(int i=1;i<M;i++)
for(int j=i;j<=n;j++)
sum[i][j]=(sum[i][j-1]+C(num[j]-i,j-i))%mod;
for(int i=1;i<(1<<m);i++){
int l=1,r=n,tot=0;
for(int j=0;j<m;j++){
if(!(i&(1<<j)))continue;
int p1=lim[j].l,p2=lim[j].r;
l=max(l,max(p[p1].l,p[p2].l)),r=min(r,min(p[p1].r,p[p2].r));
if(!vis[p1])tot++;
if(!vis[p2])tot++;
vis[p1]=vis[p2]=1;
}
for(int j=0;j<m;j++){
if(!(i&(1<<j)))continue;
int p1=lim[j].l,p2=lim[j].r;
vis[p1]=vis[p2]=0;
}
//l=max(l,tot);
if(l>r)continue;
int add=__builtin_popcount(i);
ans=(ans+(sum[tot][r]-sum[tot][l-1]+mod)*(add%2?-1:1)+mod*5)%mod;
}
printf("%lld\n",ans);
return 0;
}