#define popcount __builtin_popcount constint N = 25; int n, m; longlong y, a[N], g[N], c[N][N];
void _main() { cin >> n >> m >> y; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 0; i <= n; i++) c[i][0] = 1, c[i][i] = 1; for (int i = 0; i <= n; i++) { for (int j = 1; j < i; j++) c[i][j] = c[i - 1][j] + c[i - 1][j - 1]; } for (int s = 0; s < (1 << n); s++) { __int128 x = 1; for (int i = 1; i <= n; i++) { if (s >> (i - 1) & 1) x = x / __gcd<__int128>(x, a[i]) * a[i]; if (x > y) break; // 注意这句 } g[popcount(s)] += y / x; } longlong res = 0; for (int i = m; i <= n; i++) { if ((m - i) & 1) res -= c[i][m] * g[i]; else res += c[i][m] * g[i]; } cout << res; }
看到不好求的“恰好”,考虑二项式反演。设 fi 表示交集大小恰好为 i 的方案数,gi 表示钦定 i 个元素属于交集的方案数。
那么对于 gi,先从 n 个元素中选出 i 个,方案数 Cni。剩下 n−i 个元素可选可不选,就是求大小为 2n−i 的集合的非空子集数,答案为 22n−i−1,乘法原理:
gi=Cni(22n−i−1)
上二项式反演:
fk=i=k∑n(−1)i−kCikgi
复杂度 O(nlogn)。注意求 gi 要用欧拉定理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
constint N = 1e6 + 5; mint fac[N], ifac[N], g[N]; mint C(int n, int m){ return n < m ? 0 : fac[n] * ifac[m] * ifac[n - m]; } int n, k; void _main() { cin >> n >> k; fac[0] = ifac[0] = 1; for (int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i, ifac[i] = ~fac[i]; for (int i = 0; i <= n; i++) g[i] = C(n, i) * (mint(2).pow(mod32<1000000006>(2).pow(n - i).val) - 1); mint res = 0; for (int i = k; i <= n; i++) { if ((i - k) & 1) res -= C(i, k) * g[i]; else res += C(i, k) * g[i]; } cout << res; }
constint N = 2005; int n, m, k, a[N], b[N], last[N]; mint fac[N], ifac[N], dp[N][N], g[N]; mint C(int n, int m){ if (n < m) return0; return fac[n] * ifac[m] * ifac[n - m]; }
void _main() { cin >> n >> k; if ((n + k) & 1) return cout << 0, void(); fac[0] = ifac[0] = 1; for (int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i, ifac[i] = ~fac[i];
m = (n + k) / 2; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1; i <= n; i++) cin >> b[i]; sort(a + 1, a + n + 1), sort(b + 1, b + n + 1); for (int i = 1; i <= n; i++) last[i] = lower_bound(b + 1, b + n + 1, a[i]) - b - 1; dp[0][0] = 1; for (int i = 1; i <= n; i++) { dp[i][0] = dp[i - 1][0]; for (int j = 1; j <= i; j++) { dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1] * max(0, last[i] - j + 1); } } for (int i = 0; i <= n; i++) g[i] = dp[n][i] * fac[n - i]; mint res = 0; for (int i = m; i <= n; i++) { if ((i - m) & 1) res -= C(i, m) * g[i]; else res += C(i, m) * g[i]; } cout << res; }
constint N = 5005; int n, m, u, v, belong[N]; char c; int tot = 0, head[N]; structEdge { int next, to; } edge[N << 1]; inlinevoidadd_edge(int u, int v){ edge[++tot].next = head[u], edge[tot].to = v, head[u] = tot; } mint f[N], g[N], fac[N], ifac[N]; mint C(int n, int m){return n < m ? 0 : fac[n] * ifac[m] * ifac[n - m];}
int sz[N], cnt[2][N]; mint dp[N][N]; voiddfs(int u, int fa){ sz[u] = 1, cnt[belong[u]][u] = 1, dp[u][0] = 1; for (int j = head[u]; j != 0; j = edge[j].next) { int v = edge[j].to; if (v == fa) continue; dfs(v, u); vector<mint> f(min(sz[u] + sz[v], m), 0); for (int j = 0; j <= min(sz[u], m); j++) { for (int k = 0; k <= min(sz[v], m - j); k++) { f[j + k] += dp[u][j] * dp[v][k]; } } sz[u] += sz[v], cnt[0][u] += cnt[0][v], cnt[1][u] += cnt[1][v]; copy(f.begin(), f.end(), dp[u]); } for (int i = cnt[belong[u] ^ 1][u]; i >= 0; i--) { dp[u][i + 1] += dp[u][i] * (cnt[belong[u] ^ 1][u] - i); } }
void _main() { fac[0] = ifac[0] = 1; for (int i = 1; i < N; i++) fac[i] = fac[i - 1] * i, ifac[i] = ~fac[i]; cin >> n, m = n / 2; for (int i = 1; i <= n; i++) cin >> c, belong[i] = c ^ 48; for (int i = 1; i < n; i++) { cin >> u >> v; add_edge(u, v), add_edge(v, u); } dfs(1, -1); for (int i = 0; i <= m; i++) g[i] = dp[1][i] * fac[m - i]; for (int i = 0; i <= m; i++) { for (int j = i; j <= m; j++) { if ((j - i) & 1) f[i] -= C(j, i) * g[j]; else f[i] += C(j, i) * g[j]; } cout << f[i] << '\n'; } }