我们令 表示至少 个元素满足某个条件,其他元素随便的方案数。 表示恰好 个元素满足某个条件的方案数。一般 很好求出,但我们想求 ,就可以使用二项式反演:
形式一:
形式二:
https://www.luogu.com.cn/problem/P4071
题目描述
求有多少种 到 的排列 ,满足序列恰好有 个位置 ,使得 。
答案对 取模。多组测试数据
数据范围
对于全部的测试点,保证 ,,。
笔记
令 表示为有 个位置满足 ,剩下的位置随便放,那么就有
但是 表示的是至少有 个位置满足要求,可能满足要求的位置不止 个,我们要求的是恰好 个位置,那么令恰好 个位置满足要求的方案数为 ,有
反演:
后面那个求和式可以提前预处理出来,于是我们就可以 回答每个询问
cpp1234567891011121314151617181920212223242526272829303132#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define ls(k) (k)<<1
#define rs(k) (k)<<1|1
#define debug(x) cout<<#x<<"="<<x<<endl
using namespace std;
const int inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
#define _ 1000006
typedef pair<int,int> pii;
int fac[_],inv[_],pre[_];
inline int qpow(int a,int p,int res=1){for(;p;a=a*a%mod,p>>=1) if(p&1) res=res*a%mod;return res;}
inline void init(){
fac[0]=1;
for(int i=1;i<=1000000;i++) fac[i]=fac[i-1]*i%mod;
inv[1000000]=qpow(fac[1000000],mod-2);
for(int i=1000000-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
pre[0]=1;
for(int i=1;i<=1000000;i++) pre[i]=(pre[i-1]+(i%2==0?1:-1)*inv[i]+mod)%mod;
}
inline void subtask(){
int n,m;cin>>n>>m;
cout<<fac[n]*inv[m]%mod*pre[n-m]%mod<<endl;
}
signed main(){
init();
ios::sync_with_stdio(false);
int t;cin>>t;
while(t--) subtask();
return 0;
}
https://www.luogu.com.cn/problem/P10596
题目描述
一个有 个元素的集合有 个不同子集(包含空集),现在要在这 个集合中取出若干集合(至少一个),使得它们的交集的元素个数为 ,求取法的方案数,答案模 。
数据范围
对于 的数据,,。
笔记
设 表示交集元素数量至少为 的方案数,那么有 (先选出这 个数,然后剩下的 个数构成 个集合,这些集合随便选,但不能一个都不选)
设 表示交集元素数量恰好为 的方案数,则有
反演,有
直接求即可,其中求 的时候需要用到扩展欧拉定理
https://vjudge.net/problem/黑暗爆炸-3622
题目描述
给出长度为 的数组 和 ,这 个数字互不相同。现在让 中的数字和 中的数字两两配对,使得 中大于 中的对数比 中大于 中的对数恰好多 个,求方案数
数据范围
笔记
显然可以转化为要求配对出恰好 个 比 大的组,如果 和 不同奇偶则无解
首先对 中的数字进行排序,然后求得一个数组 , 表示 中有多少个数字可以小于 。我们发现,如果 ,那么比 小的数字一定比 小,或者说如果我们给 配对某个数之后,再考虑可供与 配对的数字个数时,可以用 减去当前已知匹配出来的组数。
于是就有 表示前 个数字匹配出来了 组,
再深入考虑一下 的含义,我们是钦定了 组,对于其他位置,我们还没有考虑怎么分配
令 ,也就是我们把其余 个位置随便配对,这些位置既可能是 比 大,也可能是 比 大,于是 就变成了至少有 组 比 大的方案数。但我们要求恰好 组的方案数,于是走个二项式反演就齐活了
cpp1234567891011121314151617181920212223242526272829303132333435363738394041#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define ls(k) (k)<<1
#define rs(k) (k)<<1|1
#define debug(x) cout<<#x<<"="<<x<<endl
using namespace std;
const int inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+9;
#define _ 2003
typedef pair<int,int> pii;
int a[_],b[_],c[_],dp[_][_],fac[_],inv[_],n,k;
inline int qpow(int a,int p,int res=1){for(;p;p>>=1,a=a*a%mod) if(p&1) res=res*a%mod;return res;}
inline int con(int n,int m){return fac[n]*inv[m]%mod*inv[n-m]%mod;};
inline int f(int x){return fac[n-x]*dp[n][x]%mod;};
inline void subtask(){
cin>>n>>k;
if((n+k)%2) return cout<<0,void();
fac[0]=1;for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
inv[n]=qpow(fac[n],mod-2);for(int i=n-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cin>>b[i];
sort(a+1,a+n+1);
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(b[j]<a[i]) c[i]++;
dp[0][0]=1;
for(int i=1;i<=n;i++){
dp[i][0]=1;
for(int j=1;j<=i;j++){
dp[i][j]=(dp[i-1][j]+dp[i-1][j-1]*max(c[i]-j+1,(int)0)%mod)%mod;
}
}
int ans=0,x=(n+k)/2;
for(int i=x;i<=n;i++) ans+=con(i,x)*((i-x)%2==1?-1:1)*f(i)%mod,ans%=mod;
cout<<(ans+mod)%mod;
}
signed main(){
ios::sync_with_stdio(false);
int t=1;//cin>>t;
while(t--) subtask();
return 0;
}