[数学记录]AT4119 [ARC096C] Everything on It

· · 个人记录

题意

n 种酱。你需要若干碗拉面,满足:

你可以在每碗拉面上放若干种酱,也可以不放,容易发现方案数为 O(2^n)

不能出现放的酱一样的两碗拉面。每一种酱至少在两碗拉面中加了。

求拉面集合的方案数。答案对给定的质数取模。

------------ 进军ATC ! 考虑容斥,设 $F(k)$ 表示钦定 $k$ 种酱不合法的方案数。 首先选出不合法的酱,方案书为 $\dbinom{n}{k}$。 首先将 $k$ 种不合法的酱安排到 $i$ 碗拉面中。 设 $g(k,i)$ 为 $k$ 种酱安排到 $i$ 碗拉面,每种都出现最多一次的方案数。 不难联想到一个很类似的数 : 第二类斯特林数 $\begin{Bmatrix}n\\m\end{Bmatrix}$ ,表示将 $n$ 个球放入无区别的 $m$ 个盒子,所有盒子都非空的方案数。 不同点在于,斯特林数中每个球必须投放一次,而 $g$ 中可以不投放。 考虑新建一个盒子当垃圾桶,但是垃圾桶又只能非空,于是新建一个 $n+1$ 号球,钦定这个球所在的盒子为垃圾桶。 这就能得到 $g(k,i)=\begin{Bmatrix}k+1\\i+1\end{Bmatrix}$。 接下来考虑其他 $n-k$ 种酱料随意选择的方案数。 可以组成 $2^{n-k}$ 种拉面,每种又可以出现或不出现,方案数为 $2^{2^{n-k}}$。 此外,这些酱还能往前面的 $i$ 碗里面加,方案数为 $(2^{n-k})^i$。 答案为 $\sum\limits_{k=0}^n(-1)^kF(k)$ ,即 : $$\sum\limits_{k=0}^n(-1)^k\binom{n}{k}2^{2^{n-k}}\sum\limits_{i=0}^k\begin{Bmatrix}k+1\\i+1\end{Bmatrix}(2^{n-k})^i$$ 计算幂的幂时需要使用费马小定理。 复杂度 $O(n^2)$。 ```cpp #include<algorithm> #include<cstdio> #define ll long long #define MaxN 3050 using namespace std; int mod,tod; ll powM(ll a,int t=mod-2){ ll ret=1; while(t){ if (t&1)ret=ret*a%mod; a=a*a%mod;t>>=1; }return ret; } ll pw2[MaxN],s[MaxN][MaxN],fac[MaxN],ifac[MaxN]; ll C(int n,int m) {return fac[n]*ifac[m]%mod*ifac[n-m]%mod;} void Init(int n) { fac[0]=1; for (int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod; ifac[n]=powM(fac[n]); for (int i=n;i;i--) ifac[i-1]=ifac[i]*i%mod; pw2[0]=1; for (int i=1;i<=n;i++) pw2[i]=pw2[i-1]*2%tod; s[0][0]=1; for (int i=1;i<=n;i++) for (int j=1;j<=i;j++) s[i][j]=(s[i-1][j-1]+s[i-1][j]*j)%mod; } int n; int main() { scanf("%d%d",&n,&mod);tod=mod-1; Init(n+1); ll ans=0; for (int k=0;k<=n;k++){ ll sav=powM(2,n-k),buf=1,sum=0; for (int i=0;i<=k;i++){ sum=(sum+s[k+1][i+1]*buf)%mod; buf=buf*sav%mod; }sum=sum*C(n,k)%mod*powM(2,pw2[n-k])%mod; if (k&1)ans-=sum;else ans+=sum; }printf("%lld",(ans%mod+mod)%mod); return 0; } ```