如果我们设 f[S] 为含有 S 中的玩具的方案数,我们只能用普通的状压DP,但复杂度高达 O(n2m),也就是 O(n2) 级别
正难则反,我们考虑设 g[S] 表示不含有 S 中的玩具的方案数,那么答案应该是 ∑(−1)||S||g[S] (||S|| 表示 S 在二进制下的位数)
考虑如何求 g[S]
我们设 f[S] 表示不含有 S 中玩具的箱子的个数,那么 g[S]=2f[S]−1
f[S] 可以用高维前缀和求出
代码
#include<iostream>#include<fstream>#include<algorithm>#include<cmath>#include<cstdlib>#include<cstring>#include<queue>#include<map>#include<set>#include<bitset>#define LL long long#define FOR(i, x, y) for(int i = (x); i <= (y); i++)#define ROF(i, x, y) for(int i = (x); i >= (y); i--)#define PFOR(i, x) for(int i = he[x]; i; i = r[i].nxt)inlineintreads(){
int sign = 1, re = 0; char c = getchar();
while(c < '0' || c > '9'){if(c == '-') sign = -1; c = getchar();}
while('0' <= c && c <= '9'){re = re * 10 + (c - '0'); c = getchar();}
return sign * re;
}
namespace MOD
{
constint mod = 1e9 + 7;
inlineintadd(int a, int b){return a + b >= mod ? a + b - mod : a + b;}
inlineintmul(int a, int b){return1ll * a * b % mod;}
inlineintsub(int a, int b){return a - b < 0 ? a - b + mod : a - b;}
inlineintfast_pow(int a, LL b){
int re = 1;
while(b)
{
if(b & 1) re = mul(re, a);
a = mul(a, a);
b >>= 1;
}
return re;
}
} usingnamespace MOD;
int n, m, all, ans;
LL f[1 << 20];
inlineintget_pop(int x){
int re = 0;
while(x) re += x & 1, x >>= 1;
return re;
}
signedmain(){
#ifndef ONLINE_JUDGEfreopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
#endif n = reads(), m = reads(), all = (1 << m) - 1;
FOR(i, 1, n)
{
int k = reads(), S = 0;
FOR(j, 1, k)
{
int a = reads();
S |= (1 << (a - 1));
}
f[all ^ S]++;
}
FOR(i, 0, m - 1) ROF(j, (1 << m) - 1, 0)
if(!(j & (1 << i))) f[j] += f[j ^ (1 << i)];
FOR(i, 0, (1 << m) - 1)
{
int k = get_pop(i);
if(k & 1) ans = sub(ans, sub(fast_pow(2, f[i]), 1));
else ans = add(ans, sub(fast_pow(2, f[i]), 1));
}
printf("%d", ans);
return0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】