牛客周赛 Round 113 题解,C++ version。

A 小红取模

直接求和取模即可。

void solve() {
    string s;
    cin >> s;
    int t = 0;
    for (auto v : s) t += v - '0';
    cout << t % 9 << "\n";
}

B 小红的复数

typedef MInt<MOD> Z;

void solve() {
    int n;
    cin >> n;
    Z a, b;
    cin >> a >> b;
    for (int i = 1; i < n; ++i) {
        Z x, y;
        cin >> x >> y;
        Z p, q;
        p = x * a - y * b;
        q = a * y + b * x;
        a = p, b = q;
    }
    cout << a << " " << b << "\n";
}

C 小红的k次方

即求数组乘积中有多少个 ,因为 ,所以对于每个元素,统计 的个数即可,最后答案为

void solve() {
    int n, c1 = 0, c2 = 0, c3 = 0;
    cin >> n;
    for (int i = 0; i < n; ++i) {
        int x;
        cin >> x;
        while (x % 2 == 0) {
            c1++;
            x /= 2;
        }
        while (x % 3 == 0) {
            c2++;
            x /= 3;
        }
        while (x % 5 == 0) {
            c3++;
            x /= 5;
        }
    }
    cout << min({c1, c2, c3}) << "\n";
}

D 小红模5

对于拼接后的数字,它模 的结果就是这个排列最后一个数字模 的结果。前面数字的排列数为

void solve() {
    ll n;
    Z ans = 0;
    cin >> n;
    for (int i = 1; i <= n; ++i) ans += i % 5;
    cout << ans*C.P(n - 1, n - 1) << "\n";
}

E 二小姐取数

对数组 做计数

  • 表示从 中选 个数,和对 取模为 的方案数。
  • 表示从 中选 个数,和对 取模为 的方案数。

再对 做前缀和, 表示从 中选不超过 个数,和对 取模为 的方案数。

最后对于每个 ,把 做模加卷积即可。

void solve() {
    int n;
    cin >> n;
    vector<int> a(n), b(n);
    for (int i = 0; i < n; ++i) cin >> a[i];
    for (int i = 0; i < n; ++i) cin >> b[i];

    vector<vector<Z>> dp1(n + 1, vector<Z>(M));
    dp1[0][0] = 1;
    for (int x : a) {
        int v = x % M;
        for (int i = n; i >= 1; --i) {
            for (int j = 0; j < M; ++j) {
                int nj = (j + v) % M;
                dp1[i][nj] += dp1[i - 1][j];
            }
        }
    }

    vector<vector<Z>> dp2(n + 1, vector<Z>(M));
    dp2[0][0] = 1;
    for (int x : b) {
        int v = x % M;
        for (int i = n; i >= 1; --i) {
            for (int j = 0; j < M; ++j) {
                int nj = (j + v) % M;
                dp2[i][nj] += dp2[i - 1][j];
            }
        }
    }

    vector<vector<Z>> pre(n + 1, vector<Z>(M));
    for (int j = 0; j < M; ++j) {
        Z s = 0;
        for (int i = 0; i <= n; ++i) {
            s += dp2[i][j];
            pre[i][j] = s;
        }
    }

    vector<Z> ans(M);
    for (int i = 0; i <= n; ++i) {
        bool f1 = true, f2 = true;
        for (int j = 0; j < M; ++j) {
            if (dp1[i][j].val() != 0) {
                f1 = false;
                break;
            }
        }
        if (f1) continue;
        for (int j = 0; j < M; ++j) {
            if (pre[i][j].val() != 0) {
                f2 = false;
                break;
            }
        }
        if (f2) continue;

        for (int rA = 0; rA < M; ++rA) {
            if (dp1[i][rA].val() == 0) continue;
            for (int rB = 0; rB < M; ++rB) {
                if (pre[i][rB].val() == 0) continue;
                int t = (rA + rB) % M;
                ans[t] += dp1[i][rA] * pre[i][rB];
            }
        }
    }

    for (int i = 0; i < M; ++i) cout << ans[i] << " ";
    cout << "\n";
}

F 二小姐的区间查询

,总共有 种类型,区间内只要统计每种类型的出现次数 ,答案就等于对所有类型对 枚举。

int encode(ll x) {
    int c1 = 0, c2 = 0, c3 = 0;
    while (c1 < 2 && x % 3 == 0) {
        x /= 3;
        c1++;
    }
    if (x % 5 == 0) c2 = 1;
    if (x % 11 == 0) c3 = 1;
    return c1 * 4 + c2 * 2 + c3;
}

void solve() {
    int n, q;
    cin >> n >> q;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; ++i) cin >> a[i];

    vector<int> type(n + 1);
    for (int i = 1; i <= n; i++) type[i] = encode(a[i]);

    vector<vector<int>> init(12, vector<int>(n + 1, 0));
    for (int i = 1; i <= n; i++) init[type[i]][i] = 1;

    vector<SegTree<int>> st;
    for (int t = 0; t < 12; t++) {
        st.eb(n);
        st[t].build(init[t]);
    }

    int c1[12], c2[12], c3[12];
    for (int t = 0; t < 12; t++) {
        c1[t] = t / 4;
        c2[t] = (t % 4) / 2;
        c3[t] = t % 2;
    }

    while (q--) {
        int op, x, y;
        cin >> op >> x >> y;
        if (op == 1) {
            int nt = encode(y);
            if (nt != type[x]) {
                st[type[x]].modify(x, 0);
                st[nt].modify(x, 1);
                type[x] = nt;
            }
        } else {
            ll cnt[12] = {0};
            for (int t = 0; t < 12; t++)
                cnt[t] = st[t].ask(x, y).val;

            ll ans = 0;
            for (int t = 0; t < 12; t++) {
                if (cnt[t] == 0) continue;
                if (c1[t] * 2 >= 2 && c2[t] * 2 >= 1 && c3[t] * 2 >= 1) {
                    ans += cnt[t] * (cnt[t] - 1) / 2;
                }
                for (int u = t + 1; u < 12; u++) {
                    if (cnt[u] == 0) continue;
                    if (c1[t] + c1[u] >= 2 && c2[t] + c2[u] >= 1 && c3[t] + c3[u] >= 1) {
                        ans += cnt[t] * cnt[u];
                    }
                }
            }
            cout << ans << "\n";
        }
    }
}

头文件

//Another
#include<bits/stdc++.h>
#include<bits/extc++.h>
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()
using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef __int128 i128;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;
typedef tuple<ll, ll, ll> TLLL;
typedef __gnu_pbds::tree<PLL, __gnu_pbds::null_type, less<PLL>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update> Tree;
// typedef __gnu_pbds::tree<ll, __gnu_pbds::null_type, less<ll>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update> Tree;

constexpr int inf = (ll)1e9 + 7;
constexpr ll INF = (ll)2e18 + 9;
// constexpr ll INF = (ll)4e18;
// constexpr ll MOD = 1e9 + 7;
constexpr ll MOD = 998244353;
constexpr ld PI = acos(-1.0);
constexpr ld eps = 1e-10;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ull randint(ull l, ull r) {uniform_int_distribution<unsigned long long> dist(l, r); return dist(rng);}

void init() {

}

void solve() {
    
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);

    init();

    int t = 1;
    cin >> t;
    for (int _ = 1; _ <= t; ++_) {
        solve();
    }
    return 0;
}

自动取模


template<int P>
struct MInt {
    int x;
    constexpr MInt() : x{} {}
    constexpr MInt(long long v) : x{norm(v % getMod())} {}

    static int Mod;
    constexpr static int getMod() {
        if (P > 0) return P;
        else return Mod;
    }
    constexpr static void setMod(int Mod_) {
        Mod = Mod_;
    }
    constexpr static int norm(long long v) {
        if (v < 0) v += getMod();
        if (v >= getMod()) v -= getMod();
        return int(v);
    }

    constexpr int val() const { return x; }
    explicit constexpr operator int() const { return x; }

    constexpr MInt operator-() const {
        return MInt(norm(getMod() - x));
    }

    constexpr MInt inv() const {
        assert(x != 0);
        return pow(getMod() - 2);
    }

    constexpr MInt pow(long long e) const {
        MInt res(1), base(*this);
        while (e > 0) {
            if (e & 1) res *= base;
            base *= base;
            e >>= 1;
        }
        return res;
    }

    constexpr MInt &operator*=(MInt rhs) & {
        x = int(1LL * x * rhs.x % getMod());
        return *this;
    }
    constexpr MInt &operator+=(MInt rhs) & {
        x = norm(x + rhs.x);
        return *this;
    }
    constexpr MInt &operator-=(MInt rhs) & {
        x = norm(x - rhs.x);
        return *this;
    }
    constexpr MInt &operator/=(MInt rhs) & {
        return *this *= rhs.inv();
    }

    friend constexpr MInt operator*(MInt lhs, MInt rhs) { return lhs *= rhs; }
    friend constexpr MInt operator+(MInt lhs, MInt rhs) { return lhs += rhs; }
    friend constexpr MInt operator-(MInt lhs, MInt rhs) { return lhs -= rhs; }
    friend constexpr MInt operator/(MInt lhs, MInt rhs) { return lhs /= rhs; }

    friend istream &operator>>(std::istream &is, MInt &a) {
        long long v;
        is >> v;
        a = MInt(v);
        return is;
    }
    friend ostream &operator<<(std::ostream &os, const MInt &a) {
        return os << a.val();
    }

    friend constexpr bool operator==(MInt lhs, MInt rhs) { return lhs.val() == rhs.val(); }
    friend constexpr bool operator!=(MInt lhs, MInt rhs) { return lhs.val() != rhs.val(); }
};

template<>
int MInt<0>::Mod = 998244353;

typedef MInt<MOD> Z;

组合数学

struct Comb {
	int n;
	vector<Z> _fac;
	vector<Z> _invfac;
	vector<Z> _inv;

	Comb() : n{0}, _fac{1}, _invfac{1}, _inv{0} {}
	Comb(int n) : Comb() {
		init(n);
	}

	void init(int m) {
		if (m <= n) return;
		_fac.resize(m + 1);
		_invfac.resize(m + 1);
		_inv.resize(m + 1);

		for (int i = n + 1; i <= m; i++) {
			_fac[i] = _fac[i - 1] * i;
		}
		_invfac[m] = _fac[m].inv();
		for (int i = m; i > n; i--) {
			_invfac[i - 1] = _invfac[i] * i;
			_inv[i] = _invfac[i] * _fac[i - 1];
		}
		n = m;
	}

	Z fac(int m) {
		if (m > n) init(2 * m);
		return _fac[m];
	}
	Z invfac(int m) {
		if (m > n) init(2 * m);
		return _invfac[m];
	}
	Z inv(int m) {
		if (m > n) init(2 * m);
		return _inv[m];
	}
	Z P(int n, int m) {
		if (n < m || m < 0) return 0;
		return fac(n) * invfac(n - m);
	}
	Z C(int n, int m) {
		if (n < m || m < 0) return 0;
		return fac(n) * invfac(m) * invfac(n - m);
	}
} C;

线段树

template<typename Int>
struct Tag {
    Int v = 0;
    void operator+=(const Tag<Int> &o) {
        v += o.v;
    }
    bool check() {
        return v != 0;
    }
};

template<typename Int>
struct Info {
    Int val = 0;
    int l, r;
    Info operator+(const Info<Int> &o) const {
        Info res;
        res.l = l;
        res.r = o.r;
        res.val = val + o.val;
        return res;
    }
    void operator+=(const Tag<Int> &o) {
        val += o.v * (r - l + 1);
    }
    bool check() {
        return l != r;
    }
};

template<typename Int>
class SegTree {
private:
    vector<Info<Int>> info;
    vector<Tag<Int>> tag;
    int n;

    int ls(int x) {return x << 1;}
    int rs(int x) {return x << 1 | 1;}

    void print(int x, int l, int r) {
        cout << x << ":[" << l << "," << r << "],val:" << info[x].val << ",tag:" << tag[x].v << "\n";
        if (l == r) return;
        int mid = l + r >> 1;
        print(ls(x), l, mid);
        print(rs(x), mid + 1, r);
    }

    template<typename Array>
    void build(int x, int l, int r, Array &data) {
        if (l == r) {
            info[x].l = l;
            info[x].r = r;
            info[x].val = data[l];
            return;
        }
        int mid = (l + r) >> 1;
        build(ls(x), l, mid, data);
        build(rs(x), mid + 1, r, data);
        info[x] = info[ls(x)] + info[rs(x)];
    }

    void push_down(int x) {
        if (tag[x].check() && info[x].check()) {
            info[ls(x)] += tag[x];
            info[rs(x)] += tag[x];
            tag[ls(x)] += tag[x];
            tag[rs(x)] += tag[x];
            tag[x] = {0};
        }
    }

    void update(int x, int l, int r, int lq, int rq, Tag<Int> v) {
        if (rq < l || lq > r) return;
        if (lq <= l && r <= rq) {
            info[x] += v;
            tag[x] += v;
            return;
        }
        push_down(x);
        int mid = (l + r) >> 1;
        update(ls(x), l, mid, lq, rq, v);
        update(rs(x), mid + 1, r, lq, rq, v);
        info[x] = info[ls(x)] + info[rs(x)];
    }

    void modify(int x, int l, int r, int pos, Int v) {
        if (r < pos || l > pos) return;
        if (l == r && l == pos) {
            info[x].val = v;
            return;
        }
        int mid = (l + r) >> 1;
        modify(ls(x), l, mid, pos, v);
        modify(rs(x), mid + 1, r, pos, v);
        info[x] = info[ls(x)] + info[rs(x)];
    }

    Info<Int> ask(int x, int l, int r, int lq, int rq) {
        if (rq < l || lq > r) return {0};
        if (lq <= l && r <= rq) return info[x];
        push_down(x);
        int mid = (l + r) >> 1;
        auto ans = ask(ls(x), l, mid, lq, rq) + ask(rs(x), mid + 1, r, lq, rq);
        return ans;
    }
public:
    SegTree(int n_): n(n_), info(4 * n_ + 1), tag(4 * n_ + 1) {}

    void print() {
        print(1, 1, n);
    }

    template<typename Array>
    void build(Array &data) {
        build(1, 1, n, data);
    }

    void update(int l, int r, Tag<Int> v) {
        update(1, 1, n, l, r, v);
    }

    void modify(int pos, Int v) {
        modify(1, 1, n, pos, v);
    }

    Info<Int> ask(int l, int r) {
        return ask(1, 1, n, l, r);
    }
};