ATR96C Everything on It 学习笔记
ATR96C Everything on It 学习笔记
题意简述
对于集合 \(\{1,2,\dots,n\}\) 的子集组成的集合中,有多少个满足 \(1,2,\dots,n\) 都在其中至少出现了两次?答案对 \(m\) 取模。
\(n\le 3\times 10^3\),\(m\le 10^9+9\),保证 \(m\) 为质数。
做法解析
这个题可以用二项式反演干掉。设 \(g(i)\) 为至少 \(i\) 个元素不合法的方案数。答案即为 \(\sum_{i=0}^n(-1)^ig(i)\binom{n}{i}\)(我们对应地设 \(f(i)\) 为恰好 \(i\) 个元素不合法的方案数,这么看我们要求的答案就是 \(f(0)\))。
\(g(i)\) 怎么求呢?对于那些只包含 \((i,n]\) 号元素的集合,选择方案显然是 \(2^{2^{n-i}}\)(\(n-i\) 种元素可以形成 \(2^{n-i}\) 种集合,而这些集合依其最终被选择的存在性与否又可以形成 \(2^{2^{n-i}}\) 个方案),至于那些钦定不合法的元素属于的集合的总方案则为,\(\sum_{j=0}^n(2^{n-i})^j\times dp_{i,j}\)(枚举 \(j\) 即枚举这些元素属于多少个集合,\(dp_{i,j}\) 意为把 \(i\) 个元素扔到这有顺序的 \(j\) 个集合或直接扔出去的方案数)。
\(dp_{i,j}\) 显然递推求得。
代码实现
很好写。注意算 \(2^{2^{n-1}}\) 的时候,内层模数为 \(p-1\)(根据欧拉定理)。
#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
using namespace omathe;
const int MaxN=3e3+5;
int N,Mod;lolo dp[MaxN][MaxN],C[MaxN][MaxN],ans;
int main(){
readis(N,Mod);
for(int i=0;i<=N;i++){
dp[i][0]=C[i][0]=1;
for(int j=1;j<=i;j++){
dp[i][j]=(dp[i-1][j-1]+(j+1)*dp[i-1][j]%Mod)%Mod;
C[i][j]=(C[i-1][j]+C[i-1][j-1])%Mod;
}
}
for(int i=0;i<=N;i++){
lolo G=fpow(2,fpow(2,N-i,Mod-1),Mod);
lolo cp=1,kp=fpow(2,N-i,Mod),sum=0;
for(int j=0;j<=i;j++,(cp*=kp)%=Mod){
(sum+=dp[i][j]*cp%Mod)%=Mod;
}
(G*=sum)%=Mod,(ans+=G*C[N][i]%Mod*(i&1?-1:1)+Mod)%=Mod;
}
writi(ans);
return 0;
}
反思总结
学完二项式反演,感觉目光都变得清澈了。
目光清澈这词是这么用的吗。好像不太对。算了不管了。
浙公网安备 33010602011771号