题解 arc096e Everything on It
Description
Solution
首先可以对第二个限制做二项式反演 .
设 \(f(i)\) 为钦定 \(i\) 种配料出现次数小于等于一次的方案数 .
那么有 \(ans=\sum\limits_i(-1)^i\binom nif(i)\)
考虑计算 \(f(i)\)
首先枚举出现次数小于等于一次的配料中有几个配料最后出现了和有几碗面中出现了这些配料 , 设有 \(j\) 个配料最后出现在了 \(k\) 碗面中 .
那么分配钦定配料的方式就是把 \(j\) 个有区别元素分成 \(k\) 个无区别非空集合的方案 , 就是 \(\begin{Bmatrix}j\\k\end{Bmatrix}\).
这 \(k\) 碗面的其他配料可以任意加而不用担心出现重复的碗 , 方案数为 \(2^{(n-i)k}\)
剩下 \(2^{n-i}\) 种面可以选或不选 , 方案数为 \(2^{2^{n-i}}\)
所以答案表达式写出即为
\(\displaystyle\sum\limits_{i=0}^n(-1)^i\binom ni\sum\limits_{j=0}^i\binom ij\sum\limits_{k=0}^j\begin{Bmatrix}j\\k\end{Bmatrix}2^{(n-i)k}2^{2^{n-i}}\)
交换求和顺序
\(\displaystyle\sum\limits_{i=0}^n(-1)^i2^{2^{n-i}}\binom ni\sum\limits_{k=0}^i2^{(n-i)k}\sum\limits_{j=k}^i\binom ij\begin{Bmatrix}j\\k\end{Bmatrix}\)
考虑用 \(O(n^2)\) 计算出所有 \(\displaystyle\sum\limits_{j=k}^i\binom ij\begin{Bmatrix}j\\k\end{Bmatrix}\)
给它一个组合意义 : 在 \(i\) 个小球中选出若干个 , 并把它们分到 \(k\) 个非空集合中的方案数 .
设该值为 \(g_{i,k}\), 那么根据上述组合意义容易得到递推式 \(g_{i,k}=(k+1)g_{i-1,k}+g_{i-1,k-1}\)
那么直接计算就完了 .
时间复杂度 \(O(n^2)\)
code
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
int read()
{
int ret=0;bool f=0;char c=getchar();
while(c>'9'||c<'0')f|=(c=='-'),c=getchar();
while(c>='0'&&c<='9')ret=(ret<<3)+(ret<<1)+(c^48),c=getchar();
return f?-ret:ret;
}
const int maxn=3e3+5;
int n,mod;
int ans;
int qpow(int a,int b,int mod=::mod){int ret=1;for(;b;b>>=1,a=(ll)a*a%mod)if(b&1)ret=(ll)ret*a%mod;return ret;}
int fac[maxn],inv[maxn],s[maxn][maxn],g[maxn][maxn];
void prework()
{
fac[0]=1;
for(int i=1;i<=n;i++)fac[i]=(ll)fac[i-1]*i%mod;
inv[n]=qpow(fac[n],mod-2);
for(int i=n-1;i>=0;i--)inv[i]=(ll)inv[i+1]*(i+1)%mod;
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]+(ll)s[i-1][j]*j%mod)%mod;
g[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=i;j++)
{
g[i][j]=(ll)g[i-1][j]*(j+1)%mod;
if(j)(g[i][j]+=g[i-1][j-1])%=mod;
}
}
}
int C(int n,int m){return (ll)fac[n]*inv[m]%mod*inv[n-m]%mod;}
int main()
{
n=read();mod=read();
prework();
for(int i=0;i<=n;i++)
{
int sum0=0;
int v=qpow(2,n-i),bas=1;
for(int k=0;k<=i;k++)(sum0+=(ll)g[i][k]*bas%mod)%=mod,bas=(ll)bas*v%mod;
sum0=(ll)sum0*C(n,i)%mod*qpow(2,qpow(2,n-i,mod-1))%mod;
if(i&1)(ans+=mod-sum0)%=mod;
else (ans+=sum0)%=mod;
}
printf("%d\n",ans);
return 0;
}