12.02训练赛
A/B. CF1614D1/D2 Divan and Kostomuksha
\(令dp[i]\)表示\(\max \sum_{i = 1}^{n} \gcd(a_1, a_2, ..., a_i), \
a_1, a_2, ..., a_i\)是一个含有因数\(i\)的元素构成的重排序列,
\(cnt[i]\)表示含有因数\(i\)的元素的个数。
有\(dp[i] = \max \limits_{j = i * prime} (dp[j] + i * (cnt[i] - cnt[j]))\)。
#include <bits/stdc++.h>
#define fu(a, b, c) for (ll a = b; a <= c; a++)
#define fd(a, b, c) for (ll a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
using namespace std;
using ll = long long;
constexpr ll N = 2e7 + 1, M = 1e6;
ll n, x, p[N], c;
ll cnt[N];
ll dp[N], ans;
bool is[N];
inline void init() {
fu(i, 2, N - 1) {
if (!is[i])
p[++c] = i;
fu(j, 1, c) {
if (p[j] * i > N - 1)
break;
is[p[j] * i] = 1;
if (!(p[j] % i))
break;
}
}
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0);
init();
cin >> n;
fu(i, 1, n) cin >> x, ++cnt[x];
fd(i, c, 1) fd(j, (N - 1) / p[i], 2) cnt[j] += cnt[j * p[i]];
cnt[1] = n;
fu(i, 1, N) dp[i] = i * cnt[i];
fd(i, N - 1, 1) fu(j, 1, c) {
if (i * p[j] >= N)
break;
mx(dp[i], dp[i * p[j]] + i * (cnt[i] - cnt[i * p[j]]));
}
cout << dp[1];
}
C. CF1614C Divan and bitwise operations
由于每个\(a_i\)都被限制条件覆盖,所以可以得到序列的按位与\(x\),
考虑有贡献的位\(i\),选择一个在该位为\(1\)的元素,对于剩余元素构成的
\(2^{n - 1}\)个集合,加入或不加入该元素分别对应的贡献为\(0\)或\(2^i\),
所以答案为\(x * {2^{n - 1}}\)。
#include <bits/extc++.h>
#include <bits/stdc++.h>
#define fu(a, b, c) for (ll a = b; a <= c; a++)
#define fd(a, b, c) for (ll a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
#define f first
#define s second
using namespace std;
using namespace __gnu_pbds;
using ll = long long;
using pll = pair<ll, ll>;
// using LL = __int128;
const int N = 1e6 + 1, M = 1e9 + 7;
// const LL M = 1e18;
ll t, n, m, l, r, k, a, b, c, f, ans;
ll d[N], fa[N], x[N];
pair<pll, ll> p[N];
vector<ll> g[N];
string S;
inline int qpow(int a, int b) {
int r = 1;
for (; b; b >>= 1, a = (ll)a * a % M)
if (b & 1)
r = (ll)r * a % M;
return r;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> t;
while (t--) {
cin >> n >> m;
b = 0;
fu(i, 1, m) cin >> l >> r >> a, b |= a;
cout << b * qpow(2, n - 1) % M << '\n';
}
}
D. CF600E Lomsat gelral
子树查询的问题,常见做法有dsu on tree,线段树合并。
#include <bits/extc++.h>
#include <bits/stdc++.h>
#define fu(a, b, c) for (ll a = b; a <= c; a++)
#define fd(a, b, c) for (ll a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
using namespace __gnu_pbds;
using namespace std;
using ll = long long;
using pll = pair<ll, ll>;
const ll N = 1e5 + 10;
ll n, u, v, now, sum, mx;
ll c[N], sz[N], son[N], cnt[N], ans[N];
vector<ll> g[N];
void dfs0(ll u, ll f) {
sz[u] = 1;
for (auto v : g[u])
if (v ^ f) {
dfs0(v, u), sz[u] += sz[v];
if (sz[v] > sz[son[u]])
son[u] = v;
}
}
void cal(ll u, ll f, ll n) {
cnt[c[u]] += n;
if (cnt[c[u]] > mx)
mx = cnt[c[u]], sum = c[u];
else if (cnt[c[u]] == mx)
sum += c[u];
for (ll v : g[u])
if (v ^ f && v ^ now)
cal(v, u, n);
}
void dfs(ll u, ll f, ll F) {
for (auto v : g[u])
if (v ^ f && v ^ son[u])
dfs(v, u, 1);
if (son[u])
dfs(son[u], u, 0), now = son[u];
cal(u, f, 1), now = 0, ans[u] = sum;
if (F)
cal(u, f, -1), sum = mx = 0;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n;
fu(i, 1, n) cin >> c[i];
fu(i, 2, n) {
cin >> u >> v;
g[u].emplace_back(v);
g[v].emplace_back(u);
}
dfs0(1, 0), dfs(1, 0, 0);
fu(i, 1, n) cout << ans[i] << ' ';
}
E. P5357 AC自动机(二次加强版)
模板题。
#include <bits/stdc++.h>
#define fu(a, b, c) for (int a = b; a <= c; a++)
#define fd(a, b, c) for (int a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
using namespace std;
const int N = 2e5 + 10;
int n;
string s, t;
struct acam {
int c[N][26]{}, val[N]{}, no[N];
int vis[N]{}, fail[N]{}, cnt = 0;
queue<int> q;
void ins(string s, int n) {
int now = 0;
fu(i, 0, s.size() - 1) {
int v = s[i] - 'a';
if (!c[now][v])
c[now][v] = ++cnt;
now = c[now][v];
}
val[now] = 1;
no[n] = now;
}
void build() {
fu(i, 0, 25) if (c[0][i]) q.push(c[0][i]);
while (q.size()) {
int u = q.front();
q.pop();
fu(i, 0, 25) {
if (c[u][i])
fail[c[u][i]] = c[fail[u]][i], q.push(c[u][i]);
else
c[u][i] = c[fail[u]][i];
}
for (int &v = fail[u]; v && !val[v]; v = fail[v])
;
}
}
void query(string s) {
int now = 0;
fu(i, 0, s.size() - 1) {
int v = s[i] - 'a';
now = c[now][v];
for (int u = now; u; u = fail[u])
vis[u] += val[u];
}
fu(i, 1, n) cout << vis[no[i]] << '\n';
}
} ac;
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n;
fu(i, 1, n) cin >> s, ac.ins(s, i);
ac.build();
cin >> t;
ac.query(t);
}
F. P7942 CONsecutive and CONcat (easy version)
把贡献分为字符串自身的贡献以及与其它字符串拼接的贡献,
由于每个字符串最少含有两种字符,所以只用考虑拼接一个字符串。
#include <bits/stdc++.h>
#define fu(a, b, c) for (ll a = b; a <= c; a++)
#define fd(a, b, c) for (ll a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
#define f first
#define s second
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pll;
const ll N = 2e6 + 10, M = 998244353;
ll t, n, m, k;
ll a, b, c, d, e = 1, f = 1, ans;
string s;
signed main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m >> k;
fu(i, 2, n - 1) e = e * i % M;
f = e * n % M;
ll pre[m][26]{}, suf[m][26]{};
fu(i, 1, n) {
cin >> s;
fu(i, 0, m - 2) if (s[i] ^ s[i + 1]) {
a = s[i] - 'a', b = i + 1;
break; // 前面有b个a
}
fd(i, m - 1, 1) if (s[i] ^ s[i - 1]) {
c = s[i] - 'a', d = m - i;
break; // 后面有d个c
}
// 字符串自身贡献
t = 0;
for (ll l = 0, r = 0; r < m;) {
while (r < m && r < l + k) {
if (s[r] ^ s[l]) {
l = r;
break;
}
++r;
if (r == l + k)
++t, ++l;
}
}
ans += t * f % M;
// 字符串拼接贡献
ll n1 = 0, n2 = 0;
for (ll i = m - 1, j = 1; i >= 1 && j <= b; --i) {
n1 += suf[i][a], mx(j, k - i);
if (i + j == k && j <= b)
ans += n1 * e % M, ++j;
}
for (ll i = m - 1, j = 1; i >= 1 && j <= d; --i) {
n2 += pre[i][c], mx(j, k - i);
if (i + j == k && j <= d)
ans += n2 * e % M, ++j;
}
++pre[b][a], ++suf[d][c];
ans %= M;
}
cout << ans;
}
G. P1494 小Z的袜子
莫队模板。
#include <bits/stdc++.h>
#define fu(a, b, c) for (ll a = b; a <= c; a++)
#define fd(a, b, c) for (ll a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
using namespace std;
using ll = long long;
using pll = pair<ll, ll>;
const ll N = 1e6 + 10, B = 224;
ll n, m, l, r, u, d, t, D, c[N], a[N];
pll ans[N];
struct q {
ll l, r, b, id;
bool operator<(q a) {
return b ^ a.b ? l < a.l : b & 1 ? r > a.r
: r < a.r;
}
} q[N];
inline void add(ll x) {
d += t, u += a[c[x]], ++a[c[x]], ++t;
}
inline void del(ll x) {
--t, --a[c[x]], d -= t, u -= a[c[x]];
}
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m;
fu(i, 1, n) cin >> c[i];
fu(i, 1, m) cin >> l >> r, q[i] = {l, r, l / B, i};
sort(q + 1, q + n + 1);
l = 1, r = 0;
fu(i, 1, m) {
while (l > q[i].l)
add(--l);
while (r < q[i].r)
add(++r);
while (l < q[i].l)
del(l++);
while (r > q[i].r)
del(r--);
if (u)
D = gcd(u, d), ans[q[i].id] = {u / D, d / D};
else
ans[q[i].id] = {0, 1};
}
fu(i, 1, n) cout << ans[i].first << '/' << ans[i].second << '\n';
}
H. P7442 维护序列
找规律题,操作1对应二进制向左rotate,操作2对应rotate后xor 1。
#include <iostream>
#define fu(a, b, c) for (int a = b; a <= c; a++)
#define fd(a, b, c) for (int a = b; a >= c; a--)
using namespace std;
const int N = 1e6 + 1;
typedef long long ll;
typedef unsigned long long ull;
ll n, m;
ull a, b, c, d;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
fu(i, 1, m) {
cin >> a >> b;
if (a ^ 1) {
ll l = b << 64 - n + c >> 64 - n, r = b >> n - c;
cout << (l + r ^ d) << '\n';
} else {
d ^= b << c;
c = (c + 1) % n;
}
}
}