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;
        }
    }
}
posted @ 2021-12-16 00:46  lemu  阅读(45)  评论(0编辑  收藏  举报
4