Educational Codeforces Round 94 (Rated for Div. 2) G
阿新 • • 發佈:2020-08-27
題意:給你n個元素,每一個元素都有一個下界和上界\([li,ri]\),表示自己所在的集合大小必須在這個範圍內。再給你m\((m<=20)\)個限制條件,每一個限制由兩個元素編號組成,表示這兩個元素不能同時出現在一個集合裡。問有多少種組成合法集合的方式。
分析:首先考慮列舉集合的大小,這個時候能選的元素就是確定的。但是會存在一些不合法的情況,就是這m個限制有可能不滿足。這個時候,我們可以把有限制的點和沒有限制的點分開考慮。因為最多會有40個點會存在限制,並且如果要合法,這些有限制的點一定是可選的點中的一個獨立集。我們可以直接考慮容斥出合法的情況。考慮到集合的大小是變化的,受限的點也是變化的,但是由於點不多,所以我們可以在可選的受限的點發生變化時,直接暴力容斥出新的合法情況就可以了。
#include<bits/stdc++.h> using namespace std; const int N = 300005; const int MOD = 998244353; vector<int> add[N], del[N]; typedef long long LL; int fac[N], inv[N]; int l[N], r[N], can[N], n, m; int a[N], b[N], id[N], in[N]; int cnt0, cnt1; void init(){ fac[0]=fac[1]=inv[1]=inv[0]=1; for(int i=2;i<=300000;++i)fac[i]=1ll*fac[i-1]*i%MOD; for(int i=2;i<=300000;++i)inv[i]=1ll*(MOD-MOD/i)*inv[MOD%i]%MOD; for(int i=2;i<=300000;++i)inv[i]=1ll*inv[i-1]*inv[i]%MOD; } int C(int n, int m){ if(m>n||m<0)return 0; return 1ll*fac[n]*inv[m]%MOD*inv[n-m]%MOD; } /* 只在受限點變化時暴力容斥,worst case:40*(1<<20),可以AC */ void dfs(int x, LL state, int coef){ if(x==m+1){ int t=__builtin_popcountll(state); for(int j=0;j<=m;++j){ can[j]=(1ll*can[j]+1ll*coef*C(cnt1-t,j-t)%MOD)%MOD; } return; } if(in[a[x]]&&in[b[x]]){ dfs(x+1,state|(1ll<<id[a[x]]-1)|(1ll<<id[b[x]]-1),MOD-coef); } dfs(x+1,state,coef); } int main(){ init(); scanf("%d%d", &n,&m); for(int i=1;i<=n;++i){ scanf("%d%d",l+i,r+i); id[i]=-1; } int idx=0; for(int i=1;i<=m;++i){ scanf("%d%d",a+i,b+i); if(id[a[i]]==-1){ id[a[i]]=++idx; } if(id[b[i]]==-1){ id[b[i]]=++idx; } } for(int i=1;i<=n;++i){ add[l[i]].push_back(i); del[r[i]].push_back(i); } int res=0; LL mask=0; can[0]=1; for(int i=1;i<=n;++i){ for(auto& x:add[i]){ in[x]=1; if(id[x]==-1){ ++cnt0; }else{ ++cnt1; } } LL nMask=0; for(int j=1;j<=m;++j){ if(in[a[j]]!=0){ nMask|=1ll<<id[a[j]]-1; } if(in[b[j]]!=0){ nMask|=1ll<<id[b[j]]-1; } } if(mask!=nMask){ mask=nMask; for(int j=0;j<=m;++j)can[j]=0; dfs(1,0,1); } for(int j=0;j<=m;++j){ res=(1ll*res+1ll*can[j]*C(cnt0,i-j))%MOD; } for(auto& x:del[i]){ in[x]=0; if(id[x]==-1){ --cnt0; }else{ --cnt1; } } } res%=MOD; if(res<0)res+=MOD; printf("%d\n",res); return 0; }