有两道题没做
A. City
直接考虑中点即可。直接枚举复杂度 Θ ( n m ) \Theta(nm) Θ(nm)。(但是也可以化简式子做到 Θ ( 1 ) \Theta(1) Θ(1))
#include <bits/stdc++.h>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vi;
int main() {
#ifdef LBT
freopen("test.in", "r", stdin);
int nol_cl = clock();
#endif
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
ll ans = 0;
for (int i = 0; i <= n; ++i)
for (int j = 0; j <= m; ++j)
ans += (min(i, n - i) * 2 + 1) * (min(j, m - j) * 2 + 1) / 2;
cout << ans;
#ifdef LBT
LOG("Time: %dms\n", int ((clock()
-nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
return 0;
}
B. Black and White
考虑如此构造:对于一个变量 v v v,在第奇数步向右走就 + 1 +1 +1 否则 − 1 -1 −1,偶数步倒过来,那么 v ∈ [ 4 k − 2 , 4 k + 1 ] v \in [4k - 2, 4k + 1] v∈[4k−2,4k+1],那么对于给定 ( n , m , v ) (n, m, v) (n,m,v) 的方案数用组合数就可以表示。事实上可以做到 Θ ( T + n + m ) \Theta(T + n + m) Θ(T+n+m),但是本代码不想判奇偶性,是 Θ ( T ( n + m ) ) \Theta(T(n+m)) Θ(T(n+m)) 的实现。
#include <bits/stdc++.h>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 100010, P = 998244353;
int fac[N * 2], ifac[N * 2];
int norm(int x) { return x >= P ? x - P : x; }
int binom(int n, int m) { return fac[n] * (ll)ifac[m] % P * ifac[n - m] % P; }
void prepare(int n) {
fac[0] = 1;
for (int i = 1; i <= n; ++i) fac[i] = fac[i - 1] * (ll)i % P;
ifac[0] = ifac[1] = 1;
for (int i = 2; i <= n; ++i) ifac[i] = -(P / i) * (ll)ifac[P % i] % P + P;
for (int i = 1; i <= n; ++i) ifac[i] = ifac[i] * (ll)ifac[i - 1] % P;
}
int calc(int n, int m, int k) {
k += n + m;
if (k & 1) return 0;
k /= 2;
for (int i = 0; i <= (n + m + 1) / 2; ++i) {
int x = i + ((n + m) / 2 - k + i), y = (n + m + 1) / 2 - i + k - i;
if ((n + m) / 2 - k + i >= 0 && (k - i) >= 0)
if (x == n && y == m)
return binom((n + m + 1) / 2, i) * (ll)binom((n + m) / 2, k - i) % P;
}
return 0;
}
int main() {
#ifdef LBT
freopen("test.in", "r", stdin);
int nol_cl = clock();
#endif
ios::sync_with_stdio(false);
cin.tie(nullptr);
prepare(200000);
int t;
cin >> t;
while (t--) {
int n, m, k;
cin >> m >> n >> k;
cout << norm(norm(calc(n, m, 4 * k - 2) + calc(n, m, 4 * k - 1)) + norm(calc(n, m, 4 * k) + calc(n, m, 4 * k + 1))) << '\n';
}
#ifdef LBT
LOG("Time: %dms\n", int ((clock()
-nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
return 0;
}
C. Dirichlet k k k-th root
考虑
k
k
k 次根就是
exp
ln
f
k
\exp \frac{\ln f}k
expklnf,由于狄利克雷卷积在
f
(
1
)
=
0
f(1)=0
f(1)=0 的乘方超过
⌊
log
2
n
⌋
\lfloor \log_2 n\rfloor
⌊log2n⌋ 次就会变成
0
0
0,那么直接暴力计算即可
Θ
(
n
log
2
n
)
\Theta(n\log ^2 n)
Θ(nlog2n) 解决。
可以考虑递推式
g
′
f
=
1
k
f
′
g
g'f=\frac1k f'g
g′f=k1f′g。
idea from _rqy: 考虑任意满足和微分相同的算子
Ω
\Omega
Ω 都能通过运算律得出
(
Ω
g
)
f
=
1
k
(
Ω
f
)
g
(\Omega g)f = \frac1k (\Omega f) g
(Ωg)f=k1(Ωf)g,因此取
Ω
D
f
:
f
n
→
ω
(
n
)
f
n
\Omega \mathfrak D_f: f_n \rightarrow \omega(n)f_n
ΩDf:fn→ω(n)fn,其中
ω
(
n
)
\omega(n)
ω(n) 是可重质因子数量。这个好在他保留
1
1
1 项以外全部信息,可以直接用于算出所有项。时间复杂度
Θ
(
n
log
n
)
\Theta(n\log n)
Θ(nlogn)。
#include <bits/stdc++.h>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 100010, L = 30, P = 998244353;
bool vis[N];
int pk[N], nv[L];
int norm(int x) { return x >= P ? x - P : x; }
void add(int& x, int y) {
if ((x += y) >= P) x -= P;
}
void sub(int& x, int y) {
if ((x -= y) < 0) x += P;
}
void exGcd(int a, int b, int& x, int& y) {
if (!b) {
x = 1;
y = 0;
return;
}
exGcd(b, a % b, y, x);
y -= a / b * x;
}
int inv(int a) {
int x, y;
exGcd(a, P, x, y);
return norm(x + P);
}
vector<int> Power(const vector<int>& f, int k) {
int n = (int)f.size() - 1;
vector<int> g(n + 1), vf = f;
for (int i = 1; i <= n; ++i) vf[i] = f[i] * (ll)pk[i] % P * k % P;
for (int i = 1; i <= n; ++i) {
int v = g[i];
g[i] = g[i] * (ll)nv[pk[i]] % P + (i == 1);
for (int j = 2, t = i + i; t <= n; t += i, ++j)
g[t] = (g[t] + g[i] * (ll)vf[j]) % P;
for (int j = 2, t = i + i; t <= n; t += i, ++j)
g[t] = (g[t] + (P - f[j]) * (ll)v) % P;
}
return g;
}
int main() {
#ifdef LBT
freopen("test.in", "r", stdin);
int nol_cl = clock();
#endif
int n, k;
scanf("%d%d", &n, &k);
vector<int> a(n + 1);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for (int i = 2; i <= n; ++i)
if (!vis[i]) {
for (int j = i; j <= n; j += i) vis[j] = true;
for (ll x = i; x <= n; x *= i)
for (int j = x; j <= n; j += x)
++pk[j];
}
nv[1] = 1;
for (int i = 2; i < L; ++i) nv[i] = -(P / i) * (ll)nv[P % i] % P + P;
a = Power(a, inv(k));
for (int i = 1; i <= n; ++i) printf("%d%c", a[i], " \n"[i == n]);
#ifdef LBT
LOG("Time: %dms\n", int ((clock()
-nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
return 0;
}
D. Fire
注意到限制非常紧,一定是一个欧拉回路但是可以少走最后一小段,记
x
(
u
)
x(u)
x(u) 如果
u
u
u 的子树要走一整遍的可允许的最晚到达
u
u
u 的时间,
y
(
u
)
y(u)
y(u) 如果
u
u
u 遍历完但是可以停在里面的最晚允许时间。
注意到按照
x
(
v
)
+
2
s
i
z
e
(
v
)
x(v) + 2size(v)
x(v)+2size(v) 的大小排序遍历子树就是使得
x
x
x 最优的方案,那么为了计算
y
y
y 需要枚举走到哪个子树里,这个只需对之前的最值用前后缀处理一下就可以快速计算。算出来的答案
<
0
< 0
<0 就无解。
总共就是一次 DFS,时间复杂度
Θ
(
n
log
n
)
\Theta(n\log n)
Θ(nlogn)。
#include <bits/stdc++.h>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vi;
const int N = 100010;
int n, k;
int a[N], s[N];
ll x[N], y[N];
vector<int> g[N];
vector<pair<pair<ll, int>, int>> greedy[N];
void dfs(int u) {
s[u] = 1;
for (int v : g[u])
if (!s[v]) {
dfs(v);
s[u] += s[v];
greedy[u].emplace_back(make_pair(x[v] - 1, s[v] * 2), v);
}
sort(greedy[u].begin(), greedy[u].end(), [&](const pair<pair<ll, int>, int>& lhs, const pair<pair<ll, int>, int>& rhs) { return rhs.first.first - lhs.first.second > lhs.first.first - rhs.first.second; });
int d = greedy[u].size();
vector<ll> dp;
dp.push_back(numeric_limits<ll>::max());
int pre = 0;
x[u] = a[u] + min(k - 2 * s[u], 0);
for (const auto& pr : greedy[u]) {
x[u] = min(x[u], pr.first.first - pre);
dp.push_back(min(dp.back(), pr.first.first - pre));
pre += pr.first.second;
}
if (d) {
vector<ll> suf(d + 1);
suf[d] = numeric_limits<ll>::max();
for (int i = d - 1; i >= 0; --i)
suf[i] = min(suf[i + 1] - greedy[u][i].first.second, greedy[u][i].first.first);
y[u] = numeric_limits<ll>::min();
pre = 0;
for (int i = 0; i < d; ++i) {
int v = greedy[u][i].second;
y[u] = max(y[u], min({y[v] - 2 * (s[u] - s[v] - 1) - 1, suf[i + 1] - pre, dp[i], (ll)a[u], a[u] + k - 2LL * (s[u] - s[v])}));
pre += greedy[u][i].first.second;
}
} else
y[u] = a[u];
}
int main() {
#ifdef LBT
freopen("test.in", "r", stdin);
int nol_cl = clock();
#endif
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> k;
for (int rep = 1; rep < n; ++rep) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
for (int i = 1; i <= n; ++i) cin >> a[i];
dfs(1);
cout << max(-1LL, y[1]) << '\n';
#ifdef LBT
LOG("Time: %dms\n", int ((clock()
-nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
return 0;
}
E. Flow
可以发现图的形态就是 1 1 1 走到 n n n 的若干条等长链,最大流显然取到 ⌊ ∑ z k ⌋ \lfloor \frac {\sum z} k \rfloor ⌊k∑z⌋,我们需要让每条链的最小值之和达到这个值。考虑每条链最小值的调整代价是凸的,将每条链上的边权排序之后将支付费用从小到大支付即可。复杂度 Θ ( n log n ) \Theta(n\log n) Θ(nlogn)。
#include <bits/stdc++.h>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 100010;
int n, m;
int s[N], nxt[N], nxtz[N], a[N];
ll support[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
int d = 0;
ll sum = 0;
memset(s, -1, sizeof(s));
for (int i = 0; i < m; ++i) {
int x, y, z;
cin >> x >> y >> z;
if (x == 1) {
++d;
s[y] = z;
} else {
nxt[x] = y;
nxtz[x] = z;
}
sum += z;
}
int p = m / d;
ll f = sum / p;
for (int i = 1; i <= n; ++i)
if (s[i] != -1) {
int k = 0;
a[++k] = s[i];
int u = i;
while (u != n) {
a[++k] = nxtz[u];
u = nxt[u];
}
sort(a + 1, a + k + 1);
for (int j = 1; j <= k; ++j)
support[j - 1] += a[j] - a[j - 1];
}
ll ans = 0, tot = support[0];
int ptr = 0;
while (tot + support[ptr + 1] < f) {
tot += support[++ptr];
ans += support[ptr] * ptr;
}
++ptr;
ans += ptr * (f - tot);
cout << ans;
return 0;
}
F. Game
非常玄学,虽然保证数据随机,然而 shuffle 会挂,但是随便爬爬山就能过,目标函数灵敏的话效果较好,比如设置成任意一种 swap 方式的剩余对方棋子数量之和。
#include <bits/stdc++.h>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
const int N = 24;
bool ok;
int a[N], b[N] = {40, 39, 38, 38, 37, 37, 36, 36, 35, 35, 34, 34, 34, 33, 33, 33, 32, 32, 32, 31, 31, 31, 30, 30};
pair<int, pair<int, int>> good[N * N];
int check() {
int x = 0, y = 0;
while (x < N && y < N) {
if (a[x] == b[y] || a[x] == 30 || b[y] == 30) {
++x;
++y;
} else if (a[x] == 31)
++(b[y] == 32 ? x : y);
else if (b[y] == 31)
++(a[x] == 32 ? y : x);
else if (a[x] > b[y])
++y;
else
++x;
}
ok &= y != N;
return x;
}
int calc() {
ok = true;
int ret = 0;
for (int i = 0; i < N; ++i)
for (int j = i + 1; j < N; ++j) {
swap(b[i], b[j]);
ret += check();
swap(b[i], b[j]);
}
return ret;
}
int main() {
#ifdef LBT
freopen("test.in", "r", stdin);
int nol_cl = clock();
#endif
ios::sync_with_stdio(false);
cin.tie(nullptr);
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
uniform_int_distribution<int> uid(0, N - 1);
int t;
cin >> t;
while (t--) {
for (int i = 0; i < N; ++i) cin >> a[i];
int cur;
while ((cur = calc()) < 22 * 23 / 2 * 24) shuffle(b, b + N, rng);
while (!ok) {
int i = uid(rng), j = uid(rng);
swap(b[i], b[j]);
int tmp = calc();
if (tmp > cur || ((tmp == cur) && (rng() & 1)) || ok)
cur = tmp;
else
swap(b[i], b[j]);
}
for (int i = 0; i < N; ++i) cout << b[i] << ' ';
cout << '\n';
}
#ifdef LBT
LOG("Time: %dms\n", int ((clock()
-nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
return 0;
}
G. Happiness
模拟。卡常
#include <bits/stdc++.h>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vi;
const int T = 10, N = 310;
int n1, n3, n6;
int n, smallest, largest, ans;
int px[N], py[N], ct[N], fst[N];
bool vis[N], eq[N];
char s[1000];
int ctm;
vi teams[N];
int pivot[N];
bool cmp(int *p1, int *p2, int k) {
while (k--) {
if (*p1 != *p2) return *p1 < *p2;
++p1;
++p2;
}
return true;
}
void dfs(int k, int penalty, int tm, int rank) {
{
int ms = numeric_limits<int>::max(), ml = -2;
if (k) {
ms = pivot[2];
ml = pivot[k + 1];
}
reverse(pivot + 2, pivot + k + 2);
while (eq[rank - 1] || rank > 1 && (pivot[0] < teams[rank - 1][0] || (pivot[0] == teams[rank - 1][0] &&
cmp(pivot + 1,
teams[rank - 1].begin().base() + 1,
k + 1))))
--rank;
reverse(pivot + 2, pivot + k + 2);
int cur = 5000 / rank;
if (rank <= n6) cur += 400;
if (rank <= n3) cur += 400;
if (rank <= n1) cur += 400;
if (ms <= smallest) cur += 700;
if (ml >= largest) cur += 500;
for (int i = 0; i < T; ++i) if (vis[i] && ct[i] <= fst[i]) cur += 800;
ans = max(ans, cur);
}
for (int i = 0; i < T; ++i)
if (!vis[i] && px[i] != -1 && tm + px[i] <= 300) {
pivot[k + 2] = ct[i] = tm + px[i];
pivot[1] = penalty + ct[i] + py[i] * 20;
pivot[0] = -k - 1;
vis[i] = true;
dfs(k + 1, pivot[1], ct[i], rank);
vis[i] = false;
pivot[1] = penalty;
pivot[0] = -k;
}
}
int main() {
#ifdef LBT
freopen("test.in", "r", stdin);
int nol_cl = clock();
#endif
ios::sync_with_stdio(false);
cin.tie(nullptr);
ctm = clock();
cin >> n;
cin.ignore();
smallest = numeric_limits<int>::max() - 1;
largest = -1;
fill(fst, fst + T, numeric_limits<int>::max());
for (int i = 1; i < n; ++i) {
cin.getline(s, 1000);
int p = 0, k = 0, penalty = 0;
vi sol;
for (int j = 0; j < T; ++j)
if (s[p] == '-') {
p += 2;
} else {
int x, y;
sscanf(s + p, "%d%d", &x, &y);
while (s[p] != ',' && s[p] != 0) ++p;
++p;
penalty += x + y * 20;
++k;
sol.push_back(x);
smallest = min(smallest, x);
largest = max(largest, x);
fst[j] = min(fst[j], x);
}
sort(sol.begin(), sol.end(), greater<int>());
teams[i].push_back(-k);
teams[i].push_back(penalty);
teams[i].insert(teams[i].end(), sol.begin(), sol.end());
}
cin.getline(s, 1000);
int p = 0;
for (int j = 0; j < T; ++j)
if (s[p] == '-') {
px[j] = -1;
p += 2;
} else {
int x, y;
sscanf(s + p, "%d%d", &x, &y);
while (s[p] != ',' && s[p] != 0) ++p;
++p;
px[j] = x;
py[j] = y;
}
sort(teams + 1, teams + n);
n1 = n / 10;
n3 = n1 * 3;
n6 = n1 * 6;
for (int i = 1; i < n; ++i)
if (teams[i] == teams[i + 1]) eq[i] = true;
dfs(0, 0, 0, n);
cout << ans;
#ifdef LBT
LOG("Time: %dms\n", int ((clock()
-nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
return 0;
}
H. King
考虑进行随机化,如果我们每次随机选取一个位置 i i i,那么 i i i 在答案序列中且 i i i 的下一个被取的位置是 i + k i + k i+k 且 k ≤ 2 k\le 2 k≤2 的概率至少是 1 4 \frac 1 4 41,因此我们随机 λ \lambda λ 次就有至少 1 − 0.7 5 λ 1 - 0.75^\lambda 1−0.75λ 的概率得到正确答案,取 λ = 50 \lambda = 50 λ=50 足够通过。时间复杂度 Θ ( λ n ) \Theta(\lambda n) Θ(λn)。
#include <bits/stdc++.h>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vi;
const int N = 200010;
int n, p;
int a[N];
int main() {
#ifdef LBT
freopen("test.in", "r", stdin);
int nol_cl = clock();
#endif
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int t;
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &p);
uniform_int_distribution<int> uid(1, n - 1);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
int ans = -1;
int rep = 50;
while (rep--) {
int i = uid(rng);
for (int t = 1; t <= min(2, n - i); ++t) {
int cur = 2;
int x = a[i], y = a[i + t];
for (int j = i - 1; j; --j)
if (x * (ll)x % p == a[j] * (ll)y % p) {
y = x;
x = a[j];
++cur;
}
x = a[i]; y = a[i + t];
for (int j = i + t + 1; j <= n; ++j)
if (y * (ll)y % p == a[j] * (ll)x % p) {
x = y;
y = a[j];
++cur;
}
if (cur * 2 >= n) ans = max(ans, cur);
}
}
printf("%d\n", ans);
}
#ifdef LBT
LOG("Time: %dms\n", int ((clock()
-nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
return 0;
}
I. Moon
计算几何,不做
J. Permutation
考虑 1 1 1 的位置,显然他左边的数不可能到右边去,如果它左边有 c c c 个数,那么可以认为他左边那 c c c 的长度内的数可以任意排列,考虑规划成子问题就是一段区间已知最左边 x c xc xc 个数是“自由”的,最右边 y c yc yc 个数是“自由”的,每次段内找最小值能否扩展即可。但是注意用于交换的数有一个更紧的位置限制,所以不是直接乘以阶乘。用线段树每次把当前找到最小的位置赋值成 + ∞ +\infty +∞,接着找次小的数如此下去。时间复杂度 Θ ( n log n ) \Theta(n\log n) Θ(nlogn)。
#include <bits/stdc++.h>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
struct Node {
int l, r;
int v;
Node *ls, *rs;
void upd() { v = min(ls->v, rs->v); }
void ch(int k, int x) {
if (l == r) {
v = x;
return;
}
(k <= ls->r ? ls : rs)->ch(k, x);
upd();
}
int qry(int l, int r) const {
if (this->l == l && this->r == r) return v;
if (r <= ls->r) return ls->qry(l, r);
if (l >= rs->l) return rs->qry(l, r);
return min(ls->qry(l, ls->r), rs->qry(rs->l, r));
}
};
const int N = 500010, P = 998244353;
int n, c, ans;
int a[N], pos[N], fac[N];
Node* segTree;
Node* build(int l, int r) {
static Node pool[N * 2], *top = pool;
Node* p = top++;
p->l = l;
p->r = r;
if (l == r) {
p->v = a[l];
return p;
}
int mid = (l + r) >> 1;
p->ls = build(l, mid);
p->rs = build(mid + 1, r);
p->upd();
return p;
}
void solve(int l, int r, int x, int y) {
while (true) {
if (r - l + 1 < (x + y) * c || l > r) {
ans = ans * (ll) fac[r - l + 1 - max(0, x - 1) - max(0, y - 1)] % P;
return;
}
int v = segTree->qry(l, r), p = pos[v];
if (p < l + x * c) {
ans = ans * (ll)(c * x - (x - 1)) % P;
++x;
segTree->ch(p, n + 1);
} else if (p > r - y * c) {
ans = ans * (ll)(c * y - (y - 1)) % P;
++y;
segTree->ch(p, n + 1);
} else {
solve(l, p - 1, x, (p - l) >= c);
solve(p + 1, r, (r - p) >= c, y);
return;
}
}
}
int main() {
#ifdef LBT
freopen("test.in", "r", stdin);
int nol_cl = clock();
#endif
fac[0] = 1;
for (int i = 1; i < N; ++i) fac[i] = fac[i - 1] * (ll)i % P;
int t;
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &c);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
pos[a[i]] = i;
}
segTree = build(1, n);
ans = 1;
solve(1, n, 0, 0);
printf("%d\n", ans);
}
#ifdef LBT
LOG("Time: %dms\n", int ((clock()
-nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
return 0;
}
K. All Pair Maximum Flow
首先最小割转平面图最短路,由于这个图是一个剖分所以没有环,一对最大流就是把叶子节点环形排成一排编号,每个 [ l , r ] ( r < n ) [l, r] (r < n) [l,r](r<n) 区间内节点和外节点的距离最小值。又考虑对于图 w ( u , v ) = w(u, v) = w(u,v)= 在树上的距离,那么一个割边必然在新图的 MST 上,我们用 DP 完成 Boruvka 过程可以算出这个 MST,然后考虑把 MST 从小到大往里加,维护一个扫描线可以求出所有答案的和。
L. Travel
码农题,不做
M. Value
注意到每个
i
k
i^k
ik 是互不相交的,也就是说我们考虑对每个
i
i
i 不能被表示为更小的数的幂,对
i
i
i 的幂对应的数枚举子集计算结果。这一复杂度必然不超过
Θ
(
(
∑
x
=
2
n
2
⌊
log
x
n
⌋
)
log
n
log
log
n
)
\Theta \left(\left(\sum_{x = 2}^n 2^{\lfloor\log_x n\rfloor}\right)\log n\log \log n\right)
Θ((x=2∑n2⌊logxn⌋)lognloglogn)
而经过近似,
n
=
1
0
5
n=10^5
n=105 时该求和不超过
3
×
1
0
5
3\times 10^5
3×105,故完全可以通过。猜测复杂度可以被分析为
Θ
(
n
log
n
log
log
n
)
\Theta(n\log n\log \log n)
Θ(nlognloglogn)。
#include <bits/stdc++.h>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vi;
const int N = 100010, L = 19;
int a[N], b[N];
int ma[L], mb[L];
bool vis[N];
int main() {
#ifdef LBT
freopen("test.in", "r", stdin);
int nol_cl = clock();
#endif
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int i = 1; i <= n; ++i) cin >> b[i];
ll ans = a[1];
for (int i = 2; i <= n; ++i) {
if (!vis[i]) {
ll cur = 0;
int cnt = 0;
for (ll x = i; x <= n; x *= i) {
vis[x] = true;
++cnt;
ma[cnt] = a[x];
mb[cnt] = b[x];
}
for (int s = 0; s < (1 << cnt); ++s) {
ll val = 0;
for (int j = 0; j < cnt; ++j) if ((s >> j) & 1) val += ma[j + 1];
for (int j = 1; j <= cnt; ++j)
if ((s >> (j - 1)) & 1)
for (int k = j + j; k <= cnt; k += j)
if ((s >> (k - 1)) & 1)
val -= mb[k];
cur = max(cur, val);
}
ans += cur;
}
}
cout << ans;
#ifdef LBT
LOG("Time: %dms\n", int ((clock()
-nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
return 0;
}