2025 暑期 mx 集训 7.29

T1

https://www.mxoj.net/problem/P110073?contestId=82

题意

给你 \(x,p\),求 \((x, y)\) 的数量满足 \(\gcd(x, y)^p = \text{lcm}(x, y)\)

\(x \leq 10^9, 1\leq p \leq 10\)

Solution

考虑 \(\gcd(x, y) = p_1^{\min(k_{1,0}, k_{1,1})} \times p_2^{\min(k_{2,0}, k_{2,1})} \times \cdots \times p_m^{\min(k_{m,0}, k_{m,1})}\)

然后 \(\text{lcm}(x, y) = p_1^{\max(k_{1,0}, k_{1,1})} \times p_2^{\max(k_{2,0}, k_{2,1})} \times \cdots \times p_m^{\max(k_{m,0}, k_{m,1})}\)

那么就是对 \(x\) 进行质因数分解,然后考虑每个质因子是作为 \(\min\) 还是 \(\max\),作为 \(\min\) 的话,那么另一个一定是 \(k_i^p\)

作为 \(\max\) 的话必须得满足 \(k_i \equiv 0 \bmod p\),那只需要把每个的方案乘起来即可。

不过 \(p = 1\) 的情况要特判掉。

Code

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 10, P = 998244353;

int main()
{
    cin.tie(0)->ios::sync_with_stdio(false);
    int x, p; cin >> x >> p;
    vector<pair<int, int>> q;
    if (p == 1) {
        cout << 1;
        return 0;
    }
    for (int i = 2; i * i <= x; i++) {
        int c = 0;
        while (!(x % i)) x /= i, c++;
        if (c) q.emplace_back(i, c);
    }
    if (x) q.emplace_back(x, 1);
    int ans = 1;
    for (auto v : q) {
        int y = v.second;
        ans = 1ll * ans * (1 + !(y % p)) % P;
    }
    cout << ans;
    return 0;
}

T2

https://www.mxoj.net/problem/P110074?contestId=82

题意

给你 \(n\) 个数 \(a_i\),你要选择一个长为 \(m\) 的首尾相接的序列 \(b\),使得 \(\max_{i = 1}^m (b_i + b_{i \bmod m} + 1)\) 最小。

\(n\leq 2\times 10^5\)

Solution

因为最大值最小,考虑二分答案。

设答案为 \(mid\),那么考虑我们选上最小的那个数一定不劣,所以直接从最小的那个数开始选。

然后我们就分别往左右扩展,能选就选,选不了就留下 \(\min(last, a_i)\),然后删掉一个。

我们维护删掉的数的个数,如果留下的数 \(\ge m\) 那就合法,然后调整二分边界即可。

Code

#include <bits/stdc++.h>

using namespace std;

const int N = 2e5 + 10, inf = 0x3f3f3f3f;

int n, m, a[N], p;

bool chk(int x)
{
    int c = 0, la = 0;
    for (int i = p; i < n; i++) {
        if (a[i] + la > x) {
            c++;
            la = min(la, a[i]);
        } else la = a[i];
    }
    int k = la;
    la = a[p];
    for (int i = p - 1; i >= 0; i--) {
        if (a[i] + la > x) {
            c++;
            la = min(la, a[i]);
        } else la = a[i];
    }
    if (la + k > x) c++;
    return c <= n - m;
}

int main()
{
    cin.tie(0)->ios::sync_with_stdio(false);
    cin >> n >> m; int mn = inf;
    for (int i = 0; i < n; i++) cin >> a[i], mn = min(mn, a[i]);
    for (int i = 0; i < n; i++) if (a[i] == mn) p = i;
    int l = 0, r = 1e9, res = 0;
    while (l <= r) {
        int mid = (l + r) / 2;
        if (chk(mid)) r = (res = mid) - 1;
        else l = mid + 1;
    }
    cout << res;
    return 0;
}

T3

https://www.mxoj.net/problem/P110075?contestId=82

题意

给你 \(n\) 个数,求有多少种划分方案使得所有划分出来的区间的 \(\text{mex}\) 相等,对 \(998244353\) 取模。

\(n\leq 3\times 10^5\)

Solution

重要性质:考虑所有划分区间的 \(\text{mex} = k\),那么 \(k\) 在整个序列中一定未出现,那么整个序列的 \(\text{mex}\) 也应该 $ = k$。

所以我们先求出整个序列的,那么我们就知道每个区间的 \(\text{mex}\) 是多少了。

那设 \(f_i\) 表示以 \(i\) 为结尾的方案,\(k\) 为整个序列的 \(\text{mex}\),转移有:

\[f_i = \sum_{j \leq i \land \text{mex}(j, i) = k} f_{j - 1} \]

初始化 \(f_0 = 1\)

然后考虑对于每个 \(i\),加的都是一个前缀,那我们只需要求出最大的 \(j\) 满足 \(\text{mex}(j, i) = k\) 然后加上前缀即可。

前缀这个可以前缀和优化,那现在在于如何对于每个 \(i\) 求出 \(j\)

因为我们求的是前缀,所以考虑倒着扫。

考虑对于目前的 \(r\) 我们求出了 \(j\),那么随着右端点左移,这个 \(j\) 肯定是左移的,不会右移,所以直接双指针然后用 set 维护 \(\text{mex}\) 即可。

时间复杂度 \(O(n \log n)\)

Code

#include <bits/stdc++.h>

using namespace std;

const int N = 3e5 + 10, P = 998244353;

int n, a[N], b[N], pre[N], f[N], s[N];

int main()
{
    cin.tie(0)->ios::sync_with_stdio(false);
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    set<int> q;
    for (int i = 0; i <= n; i++) q.insert(i);
    for (int i = 1; i <= n; i++) {
        auto p = q.find(a[i]);
        if (p != q.end()) q.erase(p);
    }
    int mex = *q.begin();
    for (int i = 0; i <= n; i++) q.insert(i);
    for (int i = n, j = n; i >= 1; i--) {
        b[a[i]]++;
        if (b[a[i]] == 1) q.erase(q.find(a[i]));
        while (j >= i && *q.begin() == mex) {
            pre[j] = i;
            b[a[j]]--;
            if (!b[a[j]]) q.insert(a[j]);
            j--;
        }
    }
    f[0] = s[0] = 1;
    for (int i = 1; i <= n; i++) {
        if (pre[i]) f[i] = s[pre[i] - 1];
        s[i] = (s[i - 1] + f[i]) % P;
    }
    cout << f[n];
    return 0;
}

T4

https://www.mxoj.net/problem/P110076?contestId=82

题意

给你 \(p\)\(n\) 个操作:

  1. 给定 \(x\)\(w = x\)
  2. 给定 \(x\)\(w = (w + x) \bmod p\)

\(w\) 初始为 \(0\)

你可以按任意顺序执行上面的操作,你要求出在 \(0 \sim p - 1\) 中有多少数无论怎样也得不到。

\(50\%\) 保证 \(n,p \leq 10^5\)

\(100\%\) 保证 \(n,p\leq 10^6\)

Solution

考虑我们可以枚举一个赋值操作,然后下边这些 \(+x\) 操作都可以选或不选。

那这就是一个 01 背包。用 bitset 优化可以做到 \(O(\frac{np}{w})\)

然后他是 \(\bmod p\) 可以断环为链在倍长,也可以直接在 bitset 转移的时候把后 \(x\) 位或到前 \(x\) 位上。

然后能过 50 分。

后面这个不会了。

Code

还未调出的代码。

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 1, N2 = 1e6 + 1;

int n, p;
bitset<N> f;
bitset<N2> g;

int main()
{
    cin.tie(0)->ios::sync_with_stdio(false);
    int _; cin >> _;
    while (_--) {
        cin >> p >> n;
        vector<int> a;
        if (p <= 1e5) {
            f.reset();
            bool ok = 1;
            for (int i = 1; i <= n; i++) {
                int opt, x; cin >> opt >> x;
                if (opt == 0) f[x] = 1, ok = 0;
                else a.push_back(x);
            }
            if (ok) f[0] = 1;
            for (auto v : a) {
                f |= (f << v) | (f >> p - v);
                for (int i = p; i <= N; i++) f[i] = 0;
            }
            int cnt = 0;
            for (int i = 0; i < p; i++) if (!f[i]) cnt++;
            cout << cnt << "\n";
        } else {
            g.reset();
            bool ok = 1;
            for (int i = 1; i <= n; i++) {
                int opt, x; cin >> opt >> x;
                if (opt == 0) g[x] = 1, ok = 0;
                else a.push_back(x);
            }
            if (ok) g[0] = 1;
            if (n > 1e5) {
                cout << 0 << "\n";
                continue;
            }
            for (auto v : a) {
                g |= (g << v) | (g >> p - v);
                for (int i = p; i <= N2; i++) g[i] = 0;
            }
            int cnt = 0;
            for (int i = 0; i < p; i++) if (!g[i]) cnt++;
            cout << cnt << "\n";
        }
    }
    return 0;
}
posted @ 2025-08-15 11:14  Dtwww  阅读(15)  评论(0)    收藏  举报