inlineintread(){ int x = 0, f = 1; char c = getchar (); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar (); } while (c >= '0' && c <='9') { x = x * 10 + (c ^ 48); c = getchar (); } return x * f; }
boolcheck(int x){ if (x % 7==0) returnfalse; for (; x; x /= 10) if (x % 10 == 7) returnfalse; returntrue; } int l[Maxn], r[Maxn], lst; bool vis[Maxn];
voidinit(){ memset (l, -1, sizeof (l)); memset (r, -1, sizeof (r)); for (int i = 1; i <= (int)1e7 + 1; ++i) { if (vis[i])continue; if (!check (i)) { for (int j = 1; i * j <= (int)1e7 + 1; j++) { vis[i * j] = 1; } } else { l[i] = lst, r[lst] = i; lst = i; } } }
intmain(){ init (); int t = read (); for (int i = 1; i <= t; ++i) { int x = read (); if (l[x] == -1 && r[x] == -1) { printf ("-1\n"); } else { printf ("%d\n", r[x]); } } }
然后写了一下 50 分 DP, 大概可以把它算成背包? fi,s 表示当前 dp 到第 i 位,已经选出来的总和为 s 的贡献(这里实际上是消掉了 j 维),枚举 i, j(现在在考虑 m 中的哪个元素), s ,最后根据 popcnt 计算合法,统计答案。
fi,s+=fi−1,s−2j×vj
复杂度 O(n2m×2m)
然后考虑优化,首先可以想到用可重集排列来优化,因为样例解释中已经给到提示了。
因为很显然 S 的大小会爆 long long ,所以要考虑把 S 维拆掉,进行一些替换。
因为在 v 中依次选择的数下标是单调的增。所以已经计算过的位就不必计较具体数值。
且可以发现,一个数对当前 s 的影响最多比当前位高 5 位,
所以思路逐渐清晰,可以将 s 拆成 k 和 s’ 分别表示已经弃掉的位置一共包含几个 1 以及 s 当前和未来 5 位。
设 fi,j,k,s′ 表示当前 dp 到选择了 i 个数,当前拓展到 v 数组第 j 位,向高位拓展 5 位为 k, 已经弃掉的位置共有 s’ 个 1 的贡献数。
嵌套枚举 i, j, k, s’, p(当前位置新选择的个数) 来更新 f 数组。
现在刷表已经不太合适了,所以改用填表。
// Code By CloudySky #include<bits/stdc++.h> #define popcnt __builtin_popcountll #define int long long namespace IO // namespace IO usingnamespace IO; constint M = 110, N = 40; constint P = 998244353; usingnamespace std;
// dp 数组, v 数组的次方 int f[N][M][N][M], v[M][N]; // 阶乘, 阶乘的逆, 线性求逆元数组 int fac[M], ifac[M], inv[M];
signedmain(){ // 预处理阶乘和阶乘的逆。 fac[1] = fac[0] = 1; ifac[1] = ifac[0] = inv[1] = 1; for (int i = 2; i <= 100; ++i) { fac[i] = fac[i - 1] * i % P; inv[i] = (P - P / i) * inv[P % i] % P; ifac[i] = ifac[i - 1] * inv[i] % P; } // 读入与预处理 v 的次方 int n = read(), m = read() + 1, K = read(); for (int i = 1; i <= m; ++i) { v[i][1] = read(), v[i][0] = 1ll; for (int j = 2; j <= n; ++j) v[i][j] = v[i][j - 1] * v[i][1] % P; } // dp f[0][0][0][0] = 1; for (int i = 0; i <= n; ++i) { for (int j = 1; j <= m; ++j) for (int k = 0; k <= K; ++k) for (int s = 0; s <= 70; ++s) for (int p = 0; p <= n - i; ++p) (f[i + p][j][k + ((s & 1) ^ (p & 1))][(s / 2) + (p / 2) + ((s & 1) && (p & 1))] += f[i][j - 1][k][s] * v[j][p] % P * ifac[p] % P) %= P; } // 统计答案 int ans = 0; for (int k = 0; k <= K; ++k) { for (int s = 0; s <= 70; ++s) if (k + popcnt(s) <= K) ans = (ans + f[n][m][k][s] * fac[n] % P) % P; } print(ans); return0; }
// Code By CloudySky #include<bits/stdc++.h> #define int long long namespace IO // namespace IO usingnamespace IO; constint Maxn = 5e5 + 10; constint inf = 1e18; usingnamespace std;
int a[Maxn], x[Maxn], f[2][Maxn];
signedmain(){ int n = read (); for (int i = 1; i <= n; ++i) a[i] = read (); n--; for (int i = 1; i <= n; ++i) x[i] = a[i + 1] - a[i]; sort (x + 1, x + n + 1); int s = 0; for (int i = 1; i <= n; ++i) s += x[i] * i; int cnt = 0, u = 0; for (int j = 0; j <= s; ++ j) f[u][j] = inf; f[0][0] = 0; for (int i = 1, d; i <= n; ++i) { if (x[i] == 0) continue; d = x[i], u ^= 1, cnt += d; for (int j = 0, k; j <= s; ++j) { f[u][j] = inf; k = j - i * d; if (k >= 0) f[u][j] = min (f[u][j], f[u ^ 1][k] + i * d * d + 2 * k * d); k = j - cnt; if (k >= 0) f[u][j] = min (f[u][j], f[u ^ 1][k] + cnt * cnt); } } int ans = inf; for (int j = 0; j <= s; ++j) if (f[u][j] < inf) ans = min (ans, (n + 1) * f[u][j] - j * j); printf ("%lld\n", ans); return0; }