The 2021 ICPC Asia Regionals Online Contest (II)

H.Set

随机。

#include <bits/stdc++.h>
using namespace std;
int main(int argc, char *argv[]) {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int k, r;
    cin >> k >> r;
    vector<int> T;
    int cnt1 = (512 - 1) / r + 1;
    for (int i = 1; i <= 256; ++i) {
        T.push_back(i <= cnt1 ? 1 : 0);
    }
    for (int i = 1; i <= k; ++i) {
        for (auto it: T) {
            cout << it;
        }
        cout << '\n';
        random_shuffle(T.begin(), T.end());
    }
    system("pause");
    return 0;
}

L.Euler Function

根据线性递推求欧拉函数我们可以得到以下结论:

对于要乘上的\(w\)我们对它分解质因数,先考虑单点\(x\)的情况,我们遍历\(w\)的所有质因子\((例如4的所有质因子包括[2,2])\)​,假如当前遍历到的为\(i\):

\(\bullet\) \(x\%i=0\):\(\phi(x \cdot i) = \phi(x) \cdot i\)

\(\bullet\) \(x\%i!=0\):\(\phi(x \cdot i) = \phi(x) \cdot (i-1)\)

对于区间乘我们可以分两种情况考虑,假如当前遍历的因子是\(i\):

\(\bullet\) 区间内每个数都有这个因子,那么我们只需要执行区间乘操作。

\(\bullet\) 否则我们直接单点暴力更新,单点乘上\(i-1\),同时给这个点的标记数组加上\(i\)这个因子。

那么本题就可以用线段树解决了,对于标记数组,可以考虑用\(bitset\)实现,这样上推的时候只需要左右儿子的\(bitset\&\)一下就可以了。

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int MAXN = 1e5 + 5;
const int MOD = 998244353;

bool isNotPrime[MAXN]; // 是否是质数
int phi[MAXN]; // 欧拉函数
int prime[MAXN], idx; // 质数
void seive(int _MAXN) {
    phi[1] = 1;
    for (int i = 2; i < _MAXN; ++i) {
        if (!isNotPrime[i]) {
            phi[i] = i - 1;
            prime[++idx] = i;
        }
        for (int j = 1; j <= idx && i * prime[j] < _MAXN; ++j) {
            isNotPrime[i * prime[j]] = true;
            // 情况一
            if (i % prime[j] == 0) {
                phi[i * prime[j]] = phi[i] * prime[j];
                break;
            }
            // 情况二
            else {
                phi[i * prime[j]] = phi[i] * (prime[j] - 1);
            }
        }
    }
}
void divide(bitset<100>&bit, int x) {
    for (int i = 2; i * i <= x; ++i) {
        if (x % i == 0) {
            bit[i] = 1;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        bit[x] = 1;
    }
}

int a[MAXN];

#define ls(x) (x) << 1
#define rs(x) (x) << 1 | 1
struct Node {
    int l, r, val, mul;
    bitset<100> bit;
    int mid() {
        return (l + r) >> 1;
    }
    int len() {
        return r - l + 1;
    }
    void update(int x) {
        if (x) {
            val = (val * x) % MOD;
            mul = (mul * x) % MOD;
        }
    }
} tree[MAXN << 2];
void pushup(int p) {
    tree[p].bit = tree[ls(p)].bit & tree[rs(p)].bit;
    tree[p].val = (tree[ls(p)].val + tree[rs(p)].val) % MOD;
}
void pushdown(int p) {
    tree[ls(p)].update(tree[p].mul);
    tree[rs(p)].update(tree[p].mul);
    tree[p].mul = 1;
}
void build(int l, int r, int p) {
    tree[p].l = l, tree[p].r = r, tree[p].mul = 1;
    if (l == r) {
        tree[p].val = phi[a[l]];
        // 先将当前给定数组的因子全部保存下来
        divide(tree[p].bit, a[l]);
        return ;
    }
    int mid = (l + r) >> 1;
    build(l, mid, ls(p));
    build(mid + 1, r, rs(p));
    pushup(p);
}
void modify(int l, int r, int k, int p) {
    if (l <= tree[p].l && tree[p].r <= r) {
        if (tree[p].bit[k]) {
            tree[p].update(k);
            return ;
        }
        if (tree[p].l == tree[p].r) {
            tree[p].bit[k] = 1;
            tree[p].update(k - 1);
            return ;
        }
    }
    pushdown(p);
    int mid = tree[p].mid();
    if (l <= mid) modify(l, r, k, ls(p));
    if (r > mid) modify(l, r, k, rs(p));
    pushup(p);
}
int query(int l, int r, int p) {
    if (l <= tree[p].l && tree[p].r <= r) {
        return tree[p].val;
    }
    pushdown(p);
    int mid = tree[p].mid(), res = 0;
    if (l <= mid) res = (res + query(l, r, ls(p))) % MOD;
    if (r > mid) res = (res + query(l, r, rs(p))) % MOD;
    return res;
}
signed main(int argc, char *argv[]) {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    seive(105);
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    build(1, n, 1);
    while (m--) {
        int opt, l, r, w;
        cin >> opt >> l >> r;
        if (opt == 1) {
            cout << query(l, r, 1) << '\n';
        }
        else {
            cin >> w;
            for (int i = 2; i * i <= w; ++i) {
                int cnt = 0;
                while (w % i == 0) {
                    ++cnt;
                    w /= i;
                }
                while (cnt--) {
                    modify(l, r, i, 1);
                }
            }
            if (w > 1) {
                modify(l, r, w, 1);
            }
        }
    }
    system("pause");
    return 0;
}
上一篇:ubuntu 18.04时区修改


下一篇:ubuntu 18.04时区修改