[BZOJ 1025] 游戏 置换群 背包DP
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ 1025] 游戏 置换群 背包DP相关的知识,希望对你有一定的参考价值。
题意
对于一个 $n$ 阶置换群 $A$ , 它的循环节大小分别为 $a_1, a_2, ..., a_m$ , 则有 $\sum_{i = 1} ^ m a_i = n$ .
定义 $f(A)$ 为它的所有循环节的最小公倍数, 即 $f(A) = [a_1, a_2, ..., a_m]$ .
求在所有 $n$ 阶置换群中, $f(A)$ 有多少种取值.
$n \le 1000$ .
分析
判断 $K$ 可不可取. $K = \prod_{i = 1} ^ r {s_r} ^ {t_r}$ 可取, 当且仅当最小的可取, 即 $\sum_{i = 1} ^ r {s_r} ^ {t_r} \le n$ .
我们考虑预处理 $1$ 到 $n$ 所有的素数, 进行 背包DP .
实现
#include <cstdio> #include <cstring> #include <cstdlib> #include <cctype> #define F(i, a, b) for (register int i = (a); i <= (b); i++) #define LL long long const int N = 1005; int n; bool v[N]; int p[N], tot; LL f[N][N], res; int main(void) { #ifndef ONLINE_JUDGE freopen("bzoj1025.in", "r", stdin); freopen("bzoj1025.out", "w", stdout); #endif scanf("%d", &n); F(i, 2, n) v[i] = true; F(i, 2, n) { if (v[i]) p[++tot] = i; for (int j = 1; j <= tot && i * p[j] <= n; j++) { v[i * p[j]] = false; if (i % p[j] == 0) break; } } f[0][0] = 1; F(i, 1, tot) F(j, 0, n) { f[i][j] = f[i-1][j]; for (int k = p[i]; j-k >= 0; k *= p[i]) f[i][j] += f[i-1][j-k]; } F(i, 0, n) res += f[tot][i]; printf("%lld\n", res); return 0; }
以上是关于[BZOJ 1025] 游戏 置换群 背包DP的主要内容,如果未能解决你的问题,请参考以下文章