https://www.luogu.com.cn/problem/AT4119
你说原来那个题面蛮好的你换了它干什么你告诉我
截一张qiuly神仙的翻译
换汤不换药啊
设\(f[i]\)表示钦定\(i\)种酱不合法的方案数,直接拿\(ANS=\sum\limits_{i=0}^n \binom{n}{i} (-1)^i f(i) \times 2^{2^{n-i}}\)
因为包含不合法酱的集合下面已经处理了,所以直接把剩下的随便选即可
考虑怎么求\(f(i)\)
设\(g(i,j)\)表示把\(i\)种酱放在\(j\)个碗里且不合法的方案数
可以得到一个显然的转移方程
\[g(i,j)=g(i-1,j-1)+g(i-1,j)\times(j+1) \]加一是因为还可以不放
然后显然
\[f(i)=\sum_{j=0}^i g(i,j) \times(2^{(n-i)})^j \]把没钦定的酱也可以加进这\(j\)个碗中,所以\(j\)次方
一步步推,不要急着跳步
code:
#include<bits/stdc++.h> #define ll long long #define N 3005 using namespace std; ll g[N][N], c[N][N]; int n, mod; ll qpow(ll x, ll y, ll mod) { y %= mod - 1; ll ret = 1; for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod; return ret; } int main() { scanf("%d%d", &n, &mod); for(int i = 0; i <= n; i ++) c[i][0] = g[i][0] = 1; for(int i = 1; i <= n; i ++) for(int j = 1; j <= i; j ++) c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod, g[i][j] = (g[i - 1][j - 1] + 1ll * (j + 1) * g[i - 1][j] % mod) % mod; // for(int i = 1; i <= n; i ++) { // for(int j = 0; j <= n; j ++) printf("%lld ", g[i][j]); printf("\n"); // } ll ans = 0; for(int i = 0; i <= n; i ++) { ll ret = 0; for(int j = 0; j <= i; j ++) (ret += g[i][j] * qpow(2, 1ll * (n - i) * j, mod) % mod) %= mod; ret = ret * c[n][i] % mod * qpow(2, qpow(2, n - i, mod - 1), mod) % mod; // printf("%lld ", ret); if(i & 1) ans = (ans - ret + mod) % mod; else ans = (ans + ret) % mod; } printf("%lld", ans); return 0; }