分类: OI笔记

  • UOJ460 新年的拯救计划

    神仙构造题…没智商..

    考虑构造出一棵树$T_0$,对于$T_0$中的任意一条边$(u,v)$,我们在第k$(0<k\leq \lfloor\frac n 2\rfloor)$棵树中添加边$((u+k)~mod~n,(v+k)~mod~n)$。

    现在考虑什么样子的$T_0$能保证对于任意$k_1\neq k_2$,均满足$((u+k_1)~mod~n,(v+k_1)~mod~n)\neq ((u+k_2)~mod~n,(v+k_2)~mod~n)$。

    首先答案一定有$\lfloor \frac n 2 \rfloor$棵生成树,那么我们可以考虑把点集分成两半,每个点集里面的边全都从某个点出发,这样我们只需要变化这个出发点,其他所有边也会跟着平移,就可以保证所有边不重复。

    设$m=\lfloor \frac n 2\rfloor$,首先令点编号从0开始。

    首先连边$(0,m)$,这条边显然在任何一棵树中都不会重复。

    对于$1\leq i\leq m-1$,连边$(0,i)$.

    对于$ m<i<n$,连边$(m,i)$。

    这样在$0+k和m+k$不重复的情况下,任何生成树内一定不会出现重复边了。

    #include <algorithm>
    #include <iostream>
    #include <tuple>
    #include <utility>
    #include <vector>
    using int_t = long long int;
    using pair_t = std::pair<int_t, int_t>;
    using std::cin;
    using std::cout;
    using std::endl;
    std::vector<pair_t> edges;
    int main() {
        int_t n;
        cin >> n;
        int_t mid = n / 2;
        edges.push_back(pair_t(0, mid));
        for (int_t i = 1; i < mid; i++) {
            edges.push_back(pair_t(0, i));
        }
        for (int_t i = mid + 1; i < n; i++) {
            edges.push_back(pair_t(mid, i));
        }
        cout << n / 2 << endl;
        for (int_t i = 0; i < n / 2; i++) {
            for (const auto& edge : edges) {
                int_t a, b;
                std::tie(a, b) = edge;
                cout << (a + i) % n + 1 << " " << (b + i) % n + 1 << " ";
            }
            cout << endl;
        }
        return 0;
    }

     

  • UOJ86 mx的组合数

    没看题解A的第一道多项式题…开心qwq

    还是一遍A的

    $$ \text{直接考虑卢卡斯定理。} \\ \text{首先考虑求出来模}p\text{为0的方案数。} \\ \text{设}n\text{的}p\text{进制下为}n_1n_2….n_k \\ \left( \begin{array}{c} x\\ n\\ \end{array} \right) =\left( \begin{array}{c} x_1\\ n_1\\ \end{array} \right) \left( \begin{array}{c} x_2\\ n_2\\ \end{array} \right) …\left( \begin{array}{c} x_k\\ n_k\\ \end{array} \right) \\ \text{显然如果存在任意}x_i<n_i,\text{则}\left( \begin{array}{c} x\\ n\\ \end{array} \right) =0\left( \text{mod }p \right) \\ \text{设}f\left( n,k \right) \text{表示考虑低}n\text{位,是否卡中}x\text{的上界时的结果多项式。} \\ \text{令}g\text{为模}p\text{意义下的原根,这个多项式的}i\text{次项的意义是选定的组合数在模}p\text{意义下为}g^i\text{的方案数。} \\ f\left( -\text{1,}true \right) =f\left( -\text{1,}false \right) =1 \\ \text{对于}i\ge \text{0,}f\left( i,false \right) =\left( \sum_{n_i\le k\le p-1}{x^y\left( \text{其中}g^y=\left( \begin{array}{c} k\\ n_i\\ \end{array} \right) \,\,\text{mod }p \right)} \right) f\left( i-\text{1,}false \right) \\ f\left( i,true \right) =x^y\left( \text{其中}g^y=\left( \begin{array}{c} x_i\\ n_i\\ \end{array} \right) \text{mod }p \right) f\left( i-\text{1,}true \right) +\left( \sum_{n_i\le k\le x_i-1}{x^y\left( \text{其中}g^y=\left( \begin{array}{c} k\\ n_i\\ \end{array} \right) \,\,\text{mod }p \right)} \right) f\left( i-\text{1,}false \right) \\ \text{所有卷积均为指数模}\varphi \left( p \right) \text{意义下的循环卷积。} \\ \text{最终}f\left( \lceil \log _px \rceil ,true \right) \text{即为结果多项式,}k\text{次项前的系数表示使得}\left( \begin{array}{c} x\\ n\\ \end{array} \right) =g^k\text{的方案数}\left( \text{不包括}0 \right) \text{。} \\ \text{复杂度}O\left( p\log p\log r \right) \\ \\ $$

    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <iostream>
    #include <vector>
    using int_t = long long int;
    using lint_t = __int128;
    
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int_t mod = 998244353;
    const int_t g0 = 3;
    const int_t LARGE = 1 << 16;
    int revs[17][LARGE];
    //模p意义下的某个数对应的原根的指数
    int_t map[LARGE];
    int_t fact[LARGE];
    std::vector<int_t> ndiv;
    int_t p, g, phi;
    lint_t n;
    int_t power(int_t base, int_t index, int_t mod = ::mod);
    void transform(int_t* A, int_t len, int_t arg);
    template <class T>
    void read(T& x) {
        x = 0;
        auto chr = getchar();
        while (isdigit(chr) == false) {
            chr = getchar();
        }
        while (isdigit(chr)) {
            x = x * 10 + chr - '0';
            chr = getchar();
        }
    }
    int_t bitRev(int_t x, int_t len) {
        int_t result = 0;
        for (int i = 1; i < len; i++) {
            result |= (x & 1);
            x >>= 1;
            result <<= 1;
        }
        return result | (x & 1);
    }
    int_t upper2n(int_t x) {
        int_t result = 1;
        while (result < x) result *= 2;
        return result;
    }
    void poly_mul(const int_t* A, const int_t* B, int_t* C) {
        static int_t Ax[LARGE], Bx[LARGE];
        std::copy(A, A + p, Ax);
        std::copy(B, B + p, Bx);
    #ifdef DEBUG
        cout << "mul " << endl;
        for (int i = 0; i < p; i++) cout << A[i] << " ";
        cout << endl;
        for (int i = 0; i < p; i++) cout << B[i] << " ";
        cout << endl;
    
    #endif
        int_t size2 = upper2n(2 * p);
        for (int_t i = p; i < size2; i++) Ax[i] = Bx[i] = 0;
    
        transform(Ax, size2, 1);
        transform(Bx, size2, 1);
        for (int_t i = 0; i < size2; i++) Ax[i] = Ax[i] * Bx[i] % mod;
        transform(Ax, size2, -1);
    #ifdef DEBUG
        cout << "mul got ";
        for (int i = 0; i < size2; i++)
            cout << Ax[i] * power(size2, -1) % mod << " ";
        cout << endl;
    #endif
        for (int_t i = phi; i < size2; i++) {
            Ax[i % phi] = (Ax[i % phi] + Ax[i]) % mod;
        }
        const auto inv = power(size2, -1, mod);
    #ifdef DEBUG
        cout << "C = ";
    #endif
        for (int_t i = 0; i < phi; i++) {
            C[i] = Ax[i] * inv % mod;
    #ifdef DEBUG
            cout << C[i] << " ";
    #endif
        }
    }
    const int_t OFFSET = 1;
    std::vector<int_t> div(lint_t x) {
        std::vector<int_t> result;
        while (x) {
            result.push_back(x % p);
            x /= p;
        }
        return result;
    }
    int_t C(int_t n, int_t m) {
        return ((fact[n] - fact[m] - fact[n - m]) % phi + phi) % phi;
    }
    void process(lint_t x, int_t* output) {
        static int_t dp[103][2][LARGE];
        memset(dp, 0, sizeof(dp));
        dp[-1 + OFFSET][0][0] = dp[-1 + OFFSET][1][0] = 1;
        auto xdiv = div(x);
        int_t size = std::max(xdiv.size(), ndiv.size()) + 1;
        xdiv.resize(size);
        ndiv.resize(size);
        for (int_t i = 0; i < size; i++) {
            // false
            {
                static int_t poly[LARGE];
                std::fill(poly, poly + p, 0);
                for (int_t j = ndiv[i]; j <= p - 1; j++) {
                    poly[C(j, ndiv[i])] += 1;
                }
                poly_mul(poly, dp[i - 1 + OFFSET][0], dp[i + OFFSET][0]);
            }
            // true
            {
                auto& curr = dp[i + OFFSET][1];
                static int_t poly[LARGE], output[LARGE];
                std::fill(poly, poly + p, 0);
                for (int_t j = ndiv[i]; j <= xdiv[i] - 1; j++)
                    poly[C(j, ndiv[i])] += 1;
                poly_mul(poly, dp[i - 1 + OFFSET][0], output);
                std::fill(poly, poly + p, 0);
                for (int j = 0; j < phi; j++) curr[j] = (curr[j] + output[j]) % mod;
                if (xdiv[i] >= ndiv[i]) poly[C(xdiv[i], ndiv[i])] += 1;
                poly_mul(poly, dp[i - 1 + OFFSET][1], output);
                for (int j = 0; j < phi; j++) curr[j] = (curr[j] + output[j]) % mod;
            }
        }
        int_t zero = x % mod;
        for (int i = 0; i < phi; i++) {
            int_t x = power(g, i, p);
            output[x] = (output[x] + dp[size - 1 + OFFSET][1][i]) % mod;
            zero = (zero - dp[size - 1 + OFFSET][1][i] + mod) % mod;
        }
        output[0] = zero;
    }
    int main() {
        for (int i = 1; i <= 16; i++) {
            for (int j = 0; j < (1 << i); j++) {
                revs[i][j] = bitRev(j, i);
            }
        }
        lint_t left, right;
        read(p);
        read(n);
        read(left);
        read(right);
        phi = p - 1;
        ndiv = div(n);
        std::vector<int_t> divisors;
        for (int_t i = 2; i * i <= phi; i++) {
            if (phi % i == 0) {
                divisors.push_back(i);
                if (i * i != phi) divisors.push_back(phi / i);
            }
        }
        for (g = 2; g <= p - 1; g++) {
            bool ok = true;
            for (int_t x : divisors) {
                if (power(g, x, p) == 1 && x != phi) {
                    ok = false;
                    break;
                }
            }
            if (ok) {
                break;
            }
        }
        for (int i = 0; i < phi; i++) map[power(g, i, p)] = i;
        for (int_t i = 2; i < p; i++) fact[i] = (fact[i - 1] + map[i]) % phi;
        static int_t rights[LARGE], lefts[LARGE];
        process(right, rights);
        process(left - 1, lefts);
        for (int i = 0; i < p; i++) {
            printf("%lld\n", (rights[i] - lefts[i] + mod) % mod);
        }
        return 0;
    }
    
    void transform(int_t* A, int_t len, int_t arg) {
        int_t size2 = log2(len);
        for (int i = 0; i < len; i++) {
            int x = revs[size2][i];
            if (x > i) std::swap(A[i], A[x]);
        }
        for (int i = 2; i <= len; i *= 2) {
            int_t mr = power(g0, arg * (mod - 1) / i, mod);
            for (int_t j = 0; j < len; j += i) {
                int_t curr = 1;
                for (int_t k = 0; k < i / 2; k++) {
                    int_t u = A[j + k], t = A[j + k + i / 2] * curr % mod;
                    A[j + k] = (u + t) % mod;
                    A[j + k + i / 2] = (u - t + mod) % mod;
                    curr = curr * mr % mod;
                }
            }
        }
    }
    
    int_t power(int_t base, int_t index, int_t mod) {
        int_t result = 1;
        if (index < 0) index = (index % (mod - 1) + mod - 1) % (mod - 1);
        while (index) {
            if (index & 1) result = result * base % mod;
            base = base * base % mod;
            index >>= 1;
        }
        return result;
    }

     

  • SCOI2016 美味

    AVX2优化暴力。

    #pragma GCC target("avx2")
    #include <immintrin.h>
    #include <inttypes.h>
    #include <algorithm>
    #include <iostream>
    using int_t = int;
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int_t LARGE = 2e5;
    
    int_t vals[LARGE + 1];
    int_t n, m;
    int_t query(int_t expe, int_t pref, int_t* left, int_t* right) {
    #ifdef DEBUG
        cout << "processing with  " << expe << "^(x+" << pref << ")" << endl;
    #endif
        int_t result = 0;
        while (int64_t(left) % 32 && left <= right) {
            result = std::max(result, expe ^ (pref + *left));
            left++;
        }
        using comp_t = __m256i;
        comp_t* ptr = (comp_t*)left;
        comp_t axs =
            _mm256_set_epi32(pref, pref, pref, pref, pref, pref, pref, pref);
        comp_t xors =
            _mm256_set_epi32(expe, expe, expe, expe, expe, expe, expe, expe);
        comp_t comps = _mm256_setzero_si256();
        while (int64_t(ptr + 1) <= int64_t(right)) {
            comp_t curr = _mm256_xor_si256(xors, _mm256_add_epi32(*ptr, axs));
            auto cmpres = _mm256_cmpgt_epi32(curr, comps);
            comps = _mm256_add_epi32(_mm256_and_si256(cmpres, curr),
                                     _mm256_andnot_si256(cmpres, comps));
            ptr += 1;
        }
        auto pint = (int_t*)ptr;
        while (pint <= right) {
            result = std::max(result, expe ^ (pref + *pint));
            pint++;
        }
        auto pack = (int_t*)&comps;
        for (int i = 0; i < 8; i++) result = std::max(result, pack[i]);
        return result;
    }
    int main() {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) scanf("%d", &vals[i]);
        for (int i = 1; i <= m; i++) {
            int expect, pref, left, right;
            scanf("%d%d%d%d", &expect, &pref, &left, &right);
            printf("%d\n", query(expect, pref, &vals[left], &vals[right]));
        }
        return 0;
    }

     

  • BZOJ2627 JZPKIL

    emm不管了…BZOJ算的是总时限我才能A..

    一开始用的拉格朗日插值,然后发现太慢,于是换成伯努利数..

    $$ \sum_{1\le i\le n}{\text{gcd}\left( i,n \right) ^x\text{lcm}\left( i,n \right) ^y} \\ =n^y\sum_{1\le i\le n}{\text{gcd}\left( i,n \right) ^{x-y}i^y} \\ =n^y\sum_{d|n}{d^{x-y}\sum_{1\le i\le n}{i^y\left[ \text{gcd}\left( i,n \right) =d \right]}} \\ =n^y\sum_{d|n}{d^x\sum_{1\le i\le \lfloor \frac{n}{d} \rfloor}{i^y\left[ \text{gcd}\left( i,\frac{n}{d} \right) =1 \right]}} \\ =n^y\sum_{d|n}{d^x\sum_{1\le i\le \lfloor \frac{n}{d} \rfloor}{i^y\sum_{k|\text{gcd}\left( i,\frac{n}{d} \right)}{\mu \left( k \right)}}} \\ =n^y\sum_{d|n}{d^x\sum_{1\le k\le \lfloor \frac{n}{d} \rfloor}{\mu \left( k \right) \sum_{1\le i\le \frac{n}{d}}{i^y\left[ k|i \right] \left[ k|\frac{n}{d} \right]}}} \\ =n^y\sum_{d|n}{d^x\sum_{k|\frac{n}{d}}{\mu \left( k \right) \sum_{k|i,i\le \frac{n}{d}}{i^y}}} \\ =n^y\sum_{d|n}{d^x\sum_{k|\frac{n}{d}}{\mu \left( k \right) k^y\sum_{1\le i\le \frac{n}{kd}}{i^y}}} \\ \text{设}S\left( n \right) =\sum_{1\le i\le n}{i^y} \\ \text{原式}=n^y\sum_{d|n}{\left( \frac{n}{d} \right) ^x\sum_{k|d}{\mu \left( k \right) k^yS\left( \frac{d}{k} \right)}} \\ =n^y\sum_{k|n}{\mu \left( k \right) k^y\sum_{k|d,d|n}{S\left( \frac{ik}{k} \right) \left( \frac{n}{ik} \right) ^x}} \\ =n^y\sum_{k|n}{\mu \left( k \right) k^y\sum_{1\le i\le \frac{n}{k},i|\frac{n}{k}}{S\left( i \right) \left( \frac{n}{ik} \right) ^x}} \\ =n^y\sum_{k|n}{\mu \left( k \right) k^y\sum_{i|\frac{n}{k}}{S\left( i \right) \left( \frac{n}{ik} \right) ^x}} \\ =n^y\sum_{k|n}{\mu \left( \frac{n}{k} \right) \left( \frac{n}{k} \right) ^y\sum_{d|k}{S\left( d \right) \left( \frac{k}{d} \right) ^x}} \\ =n^y\sum_{d|n}{S\left( d \right) \sum_{i|\frac{n}{d}}{\mu \left( \frac{n}{id} \right) \left( \frac{n}{id} \right) ^y}}\left( i \right) ^x \\ =n^y\sum_{d|n}{S\left( d \right) \left( \frac{n}{d} \right) ^x\sum_{i|\frac{n}{d}}{\mu \left( i \right) \left( \frac{1}{i} \right) ^{x-y}}} \\ \text{此时如果}x=y,\text{则原式}=n^y\sum_{d|n}{S\left( d \right) \left( \frac{n}{d} \right) ^x\left[ n=d \right] =n^yS\left( n \right)} \\ \text{否则原式}=n^y\sum_{d|n}{S\left( d \right) \left( \frac{n}{d} \right) ^x\prod_{p\,\,| \frac{n}{d}\,\,and\,\,p\,\,is\,\,a\,\,prime}{\left( 1-\left( \frac{1}{p} \right) ^{x-y} \right)}}\left( x\ne y \right) \\ \text{设}f\left( n \right) =\prod_{p\,\,| n\,\,and\,\,p\,\,is\,\,a\,\,prime}{\left( 1-\left( \frac{1}{p} \right) ^{x-y} \right)},f\text{函数可以在枚举约数时顺便处理出来} \\ \\ \text{又因为}S\left( n \right) =\sum_{1\le i\le n}{i^y}=\frac{1}{y+1}\sum_{0\le i\le y}{\left( \begin{array}{c} y+1\\ i\\ \end{array} \right) B_in^{y+1-i}} \\ =\frac{1}{y+1}\sum_{-y\le -i\le 0}{\left( \begin{array}{c} y+1\\ i\\ \end{array} \right) B_in^{y+1-i}} \\ =\frac{1}{y+1}\sum_{0\le y-i\le y}{\left( \begin{array}{c} y+1\\ i\\ \end{array} \right) B_in^{y+1-i}} \\ =\frac{1}{y+1}\sum_{1\le y-i+1\le y+1}{\left( \begin{array}{c} y+1\\ y-i+1\\ \end{array} \right) B_{y-i+1}n^{y+1-\left( y-i+1 \right)}} \\ =\frac{1}{y+1}\sum_{1\le i\le y+1}{\left( \begin{array}{c} y+1\\ i\\ \end{array} \right) B_{y-i+1}n^i} \\ \text{故预处理出伯努利数后,可以在}O\left( n \right) \text{的时间内计算出多项式}S\left( n \right) \\ \text{由于}\sum_{0\le i\le m}{\left( \begin{array}{c} m+1\\ i\\ \end{array} \right) B_i=\left[ m=0 \right]} \\ \text{故}B_0=\text{1,对于}i>0 \\ \left( \begin{array}{c} m+1\\ m\\ \end{array} \right) B_m+\sum_{0\le i<m}{\left( \begin{array}{c} m+1\\ i\\ \end{array} \right) B_i=0} \\ B_m=-\frac{\sum_{0\le i<m}{\left( \begin{array}{c} m+1\\ i\\ \end{array} \right) B_i}}{m+1} \\ $$

    #include <inttypes.h>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <random>
    #include <unordered_map>
    #include <utility>
    #include <vector>
    #define debug(x) std::cout << #x << " = " << x << std::endl;
    
    typedef long long int int_t;
    
    using std::cin;
    using std::cout;
    using std::endl;
    
    using pair_t = std::pair<int_t, int_t>;
    
    const int_t mod = 1e9 + 7;
    const int_t LARGE = 3003;
    int_t B[LARGE + 10], fact[LARGE + 10], factInv[LARGE + 10];
    std::mt19937 gen;
    int_t mul(int_t a, int_t b, int_t mod) { return (__int128_t)a * b % mod; }
    int_t C(int_t n, int_t m) {
        return fact[n] * factInv[m] % mod * factInv[n - m] % mod;
    }
    int_t power(int_t base, int_t index, int_t mod) {
        int_t result = 1;
        if (index < 0) {
            index += mod - 1;
        }
        while (index) {
            if (index & 1) result = mul(result, base, mod);
            index >>= 1;
            base = mul(base, base, mod);
        }
        return result;
    }
    bool isPrime(int_t n) {
        if (n <= 1) return false;
        if (n == 2 || n == 3) return true;
        int_t s = 0, t = n - 1;
        while (t % 2 == 0) {
            t /= 2;
            s++;
        }
        std::uniform_int_distribution<int_t> rand_int(2, n - 1);
        for (int_t _i = 1; _i <= 3; _i++) {
            int_t a = rand_int(gen);
            int_t prev = power(a, t, n);
            for (int_t i = 1; i <= s; i++) {
                int_t curr = mul(prev, prev, n);
                if (curr == 1 && prev != 1 && prev != n - 1) return false;
                prev = curr;
            }
            if (prev != 1) return false;
        }
        return true;
    }
    int_t gcd(int_t a, int_t b) {
        if (b == 0) return a;
        return gcd(b, a % b);
    }
    int_t getFactor(int_t n, int_t c) {
        const auto f = [=](int_t x) { return (mul(x, x, n) + c) % n; };
        std::uniform_int_distribution<int_t> rand_int(2, n - 1);
        int_t x = rand_int(gen), y = rand_int(gen);
        int_t i = 0, k = 2;
        int_t prod = 1, factor = 1;
        while (true) {
            i++;
            x = f(x);
            prod = mul(prod, std::abs(x - y), n);
            if (i % 256 == 0) {
                factor = gcd(prod, n);
                if (factor > 1) return factor;
            }
            if (x == y) return n;
            if (i == k) {
                i = 0;
                k *= 2;
                y = x;
                factor = std::max(factor, gcd(n, prod));
                if (factor > 1) return factor;
                prod = 1;
                factor = 1;
            }
        }
    }
    template <class CT>
    void pollardRho(int_t n, CT& output) {
        if (isPrime(n)) {
            output[n] += 1;
            return;
        }
        int_t seed = gen();
        int_t factor = n;
        while (factor == n) {
            factor = getFactor(factor, seed--);
            if (seed == 0) seed = gen();
        }
        pollardRho(factor, output);
        pollardRho(n / factor, output);
    }
    void getPoly(int_t y, int_t* output) {
        int_t prod = power(y + 1, mod - 2, mod);
        output[0] = 0;
        for (int_t i = 1; i <= y + 1; i++)
            output[i] = C(y + 1, i) * B[y - i + 1] % mod * prod % mod;
    }
    void DFS(int_t n, const std::unordered_map<int_t, int_t>& primeVals,
             std::vector<pair_t>& counts, int_t prod, int_t funcProd,
             std::vector<pair_t>& output) {
        if (n >= counts.size()) {
    #ifdef DEBUG
            cout << "divisor " << prod << " func " << funcProd << endl;
    #endif
            output.push_back(pair_t(prod, funcProd));
            return;
        }
        //²»¿¼ÂÇÕâ¸öÒòÊý
    #ifdef DEBUG
        cout << "setting " << counts[n].first << " time to " << 0
             << " and prev = " << 1 << "curr n = " << n << endl;
    #endif
        DFS(n + 1, primeVals, counts, prod, funcProd, output);
        int_t prev = counts[n].first;
        for (int_t i = 1; i <= counts[n].second; i++) {
    #ifdef DEBUG
            cout << "setting " << counts[n].first << " time to " << i
                 << " and prev = " << prev << "curr n = " << n << endl;
    #endif
            DFS(n + 1, primeVals, counts, prod * prev,
                funcProd * primeVals.at(counts[n].first) % mod, output);
            prev = prev * counts[n].first;
        }
    #ifdef DEBUG
        cout << "backing " << endl;
    #endif
    }
    int_t process(int_t n, int_t x, int_t y) {
        static int_t poly[LARGE + 10];
        memset(poly, 0, sizeof(poly));
        getPoly(y, poly);
        const auto sub = [&](int_t x) {
            //ÌØÅÐy=0
            if (y == 0) return x;
            int_t result = 0;
            int_t pow = 1;
            x %= mod;
            x += 1;
            for (int_t i = 1; i <= y + 1; i++) {
                result = (result + poly[i] * pow % mod) % mod;
                pow = pow * x % mod;
            }
    #ifdef DEBUG
            cout << "sub " << x << " = " << result << endl;
    #endif
            return result;
        };
    #ifdef DEBUG
        while (true) {
            int_t x;
            cin >> x;
            cout << sub(x) << endl;
        }
    #endif
        if (x == y) {
            return power(n, y, mod) * sub(n) % mod;
        }
        std::unordered_map<int_t, int_t> output;
        pollardRho<std::unordered_map<int_t, int_t>>(n, output);
    #ifdef DEBUG
        for (const auto& kvp : output)
            cout << kvp.first << " = " << kvp.second << endl;
    #endif
        std::unordered_map<int_t, int_t> primeVals;
        std::vector<pair_t> counts;
        std::vector<pair_t> divisors;
        std::unordered_map<int_t, int_t> func;
        for (const auto& kvp : output) {
            primeVals[kvp.first] =
                (1 - power(kvp.first, (y - x + mod - 1) % (mod - 1), mod) + mod) %
                mod;
            counts.push_back(kvp);
        }
        DFS(0, primeVals, counts, 1, 1, divisors);
        for (const auto& kvp : divisors) {
            func[kvp.first] = kvp.second;
        }
        int_t result = 0;
        for (const auto& kvp : divisors) {
            int_t d = kvp.first;
            result = (result + sub(d) * power(n, x, mod) % mod *
                                   power(d, mod - 1 - x, mod) % mod * func[n / d] %
                                   mod) %
                     mod;
    #ifdef DEBUG
            cout << "divisor " << d << " count "
                 << sub(d) * power(n, x, mod) % mod * power(d, mod - 1 - x, mod) %
                        mod * func[n / d] % mod
                 << endl;
    #endif
        }
        result = result * power(n, y, mod) % mod;
        return result;
    }
    
    int main() {
        fact[0] = fact[1] = factInv[0] = factInv[1] = 1;
        for (int_t i = 2; i <= LARGE + 2; i++) {
            fact[i] = fact[i - 1] * i % mod;
            factInv[i] = (mod - mod / i) * factInv[mod % i] % mod;
        }
        for (int_t i = 2; i <= LARGE + 2; i++)
            factInv[i] = factInv[i - 1] * factInv[i] % mod;
        B[0] = 1;
        for (int_t i = 1; i <= LARGE + 2; i++) {
            int_t sum = 0;
            for (int_t j = 0; j < i; j++)
                sum = (sum + C(i + 1, j) * B[j] % mod) % mod;
            B[i] = (mod - sum) * power(i + 1, mod - 2, mod) % mod;
    #ifdef DEBUG
            if (i <= 10) cout << "B " << i << " = " << B[i] << endl;
    #endif
        }
        gen.seed(std::random_device()());
        int_t T;
        cin >> T;
        while (T--) {
            int_t n, x, y;
            cin >> n >> x >> y;
            cout << process(n, x, y) << endl;
        }
        return 0;
    }

     

  • LOJ6029 市场

    不会势能分析..

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <inttypes.h>
    #include <cmath>
    #define debug(x) std::cout << #x << " = " << x << std::endl;
    
    using int_t = long long int;
    
    using std::cin;
    using std::endl;
    using std::cout;
    const int_t INF = 0x7fffffff;
    
    const int_t LARGE = 1e5;
    void* allocate();
    struct Node {
    	Node* left = nullptr,*right = nullptr;
    	int begin,end;
    	int_t sum = 0;
    	int minval = INF;
    	int maxval = -INF;
    	//±äÁ¿Î´³õʼ»¯
    	int mark = 0;
    	Node(int begin,int end) {
    		this -> begin = begin;
    		this -> end = end;
    	}
    	void maintain() {
    		if(begin != end) {
    			sum = left -> sum + right -> sum;
    			minval = std::min(left->minval,right -> minval);
    			maxval = std::max(left -> maxval ,right -> maxval);
    		}
    	}
    	void add(int x) {
    		mark += x;
    		minval += x;
    		maxval += x;
    		sum += (int_t)(end - begin + 1) * x;
    #ifdef DEBUG
    		cout<<"adding "<<x<<" at node "<<this->begin<<" "<<this->end<<" "<<sum<<" "<<mark<<" "<<minval<<" "<<maxval<<endl;
    #endif
    	}
    	void pushDown() {
    		if(begin != end) {
    			left -> add(mark);
    			right -> add(mark);
    			mark = 0;
    		}
    	}
    	void add(int begin,int end,int val) {
    		if(end < this -> begin || begin > this -> end) return;
    #ifdef DEBUG
    		cout<<"adding "<<val<<" for "<<begin<<" "<<end<<" at "<<this->begin<<" "<<this->end<<endl;
    #endif
    		if(this -> begin >= begin && this -> end <= end) {
    #ifdef DEBUG
    			cout<<"dir add at "<<this->begin<<" "<<this->end<<" "<<val<<endl;
    #endif
    			this -> add(val);
    			return;
    		}
    		pushDown();
    		left -> add(begin,end,val);
    		right -> add(begin,end,val);
    		maintain();
    	}
    	int_t querySum(int begin,int end) {
    		if(end < this -> begin || begin > this -> end) return 0;
    		if(this -> begin >= begin && this -> end <= end) {
    			return this -> sum;
    		}
    		pushDown();
    		return left -> querySum(begin,end) + right -> querySum(begin,end);
    	}
    	int queryMin(int begin,int end) {
    		if(end < this -> begin || begin > this -> end ) return INF;
    		if(this -> begin >= begin && this -> end <= end) return this -> minval;
    		pushDown();
    		return std::min(left -> queryMin(begin,end),right -> queryMin(begin,end));
    	}
    	void divide(int x) {
    #ifdef DEBUG
    		cout<<"div "<<x<<" at node "<<this->begin<<" "<<this->end<<endl;
    #endif
    		if(int_t(this -> maxval - floor((double)this -> maxval / x)) == int_t(this -> minval - floor((double)this -> minval / x))) {
    			this -> add(-(this -> maxval - floor((double)this -> maxval / x)));
    			return;
    		}
    		pushDown();
    		left -> divide(x);
    		right -> divide(x);
    		maintain();
    	}
    	void divide(int begin,int end,int val) {
    		if(end < this -> begin || begin > this -> end) return;
    		if(this -> begin >= begin && this -> end <= end) {
    			this -> divide(val);
    			return;
    		}
    		pushDown();
    		left -> divide(begin,end,val);
    		right -> divide(begin,end,val);
    		maintain();
    	}
    	static Node* build(int begin,int end,int* val) {
    		Node* node = new (allocate()) Node(begin,end);
    		if(begin != end) {
    			int_t mid = (begin + end) / 2;
    			node -> left = build(begin,mid,val);
    			node -> right = build(mid + 1 ,end ,val);
    			node -> maintain();
    		} else {
    			node -> sum = node -> minval = node -> maxval = val[begin];
    		}
    		return node;
    	}
    };
    void* allocate(){
        const int_t SIZE = 3e5;
        static char buf[SIZE * sizeof(Node)];
        static int_t used = 0;
        return buf + (++used) * sizeof(Node);
    }
    
    int val[LARGE + 1];
    int n,m;
    int main() {
    	scanf("%d%d",&n,&m);
    	for(int_t i = 1; i <= n; i ++) scanf("%d",&val[i]);
    	Node* root = Node::build(1,n,val);
    	for(int_t i = 1; i <= m; i ++) {
    		int opt,left,right,val;
    		scanf("%d%d%d",&opt,&left,&right);
    		left += 1;
    		right += 1;
    		if(opt == 1) {
    			scanf("%d",&val);
    			root -> add(left,right,val);
    		} else if(opt == 2) {
    			scanf("%d",&val);
    			root -> divide(left,right,val);
    		} else if(opt == 3) {
    			printf("%d\n",root->queryMin(left,right));
    		} else if(opt == 4) {
    			printf("%lld\n",root->querySum(left,right));
    		}
    	}
    	return 0;
    }

     

  • 算法与数据结构整理

    Min25筛

    //注意要存2sqrtN个数。
    #include <algorithm>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using int_t = long long int;
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int_t LARGE = 1e5 + 1;
    
    bool isPrime[LARGE + 1];
    int_t primes[LARGE + 1];
    // S0->所有质数的个数,S1->所有质数的和
    int_t S0[LARGE + 1], S1[LARGE + 1];
    int_t numbers[LARGE + 1], hash0[LARGE + 1], hash1[LARGE + 1];
    int_t g0[LARGE + 1], g1[LARGE];
    int_t S1p(int_t n) { return n * (n + 1) / 2; }
    void init() {
        memset(isPrime, 1, sizeof(isPrime));
        isPrime[1] = false;
        for (int_t i = 2; i <= LARGE; i++) {
            if (isPrime[i]) {
                for (int_t j = i * i; j <= LARGE; j += i) {
                    isPrime[j] = false;
                }
                primes[++primes[0]] = i;
                int_t next = primes[0];
                S0[next] = S0[next - 1] + 1;
                S1[next] = S1[next - 1] + i;
    #ifdef DEBUG
                if (i <= 20) {
                    cout << "prime " << next << " = " << i << " S0 = " << S0[next]
                         << " S1 " << S1[next] << endl;
                }
    #endif
            }
        }
    }
    int_t Sphi(int_t n, int_t k, const int_t sqrt, const int_t nx) {
        if (n <= 1 || primes[k] > n) return 0;
        int_t result = -(S1[k - 1] - S0[k - 1]);
        //质数贡献的答案
        if (n <= sqrt) {
            result += g1[hash0[n]] - g0[hash0[n]];
        } else {
            result += g1[hash1[nx / n]] - g0[hash1[nx / n]];
        }
        // #ifdef DEBUG
        //     cout << "processing n = " << n << " k =" << k << " aka " << primes[k]
        //          << endl;
        //     cout << "prime answers " << result << endl;
        // #endif
        //枚举质因子
        for (int_t i = k; primes[i] * primes[i] <= n && i <= primes[0]; i++) {
            //枚举质因子的次数
            for (int_t p = primes[i]; p * primes[i] <= n; p *= primes[i]) {
                //利用积性函数的性质,除掉最小质因子的幂继续递归
                result += (Sphi(n / p, i + 1, sqrt, nx)) * (p - p / primes[i]) +
                          p * primes[i] - p;
            }
        }
        return result;
    }
    int_t Smu(int_t n, int_t k, const int_t sqrt, const int_t nx) {
        if (n <= 1 || primes[k] > n) return 0;
        int_t result = -(-S0[k - 1]);
        if (n <= sqrt)
            result += (-g0[hash0[n]]);
        else
            result += (-g0[hash1[nx / n]]);
        //枚举质因子
        for (int_t i = k; primes[i] * primes[i] <= n && i <= primes[0]; i++) {
            result += Smu(n / primes[i], i + 1, sqrt, nx) * (-1);
        }
        return result;
    }
    void process(int_t n) {
        numbers[0] = 0;
        int_t sqrt = ::sqrt(n);
    // k=0时候的答案
    #ifdef DEBUG
        cout << "at k = 0" << endl;
    #endif
        for (int_t i = 1, next; i <= n; i = next + 1) {
            next = n / (n / i);
            int_t curr = n / i;
            int_t id = ++numbers[0];
            numbers[id] = curr;
            if (curr <= sqrt) {
                hash0[curr] = id;
            } else {
                hash1[n / curr] = id;
            }
            g0[id] = (n / i) - 1;
            g1[id] = S1p(n / i) - 1;
    #ifdef DEBUG
            cout << "number " << n / i << " id = " << id << " g0 = " << g0[id]
                 << " g1 = " << g1[id] << endl;
    #endif
        }
        //从k=1开始
        for (int_t k = 1; k <= primes[0]; k++) {
            // #ifdef DEBUG
            //         cout << "before prime " << k << " aka " << primes[k] << endl;
            //         for (int_t i = 1; i <= numbers[0]; i++) {
            //             cout << "number " << i << " aka " << numbers[i] << " g0 =
            //             " << g0[i]
            //                  << " g1 = " << g1[i] << endl;
            //         }
            // #endif
            //只有质数平方不超过i才有贡献
            for (int_t i = 1;
                 i <= numbers[0] && primes[k] * primes[k] <= numbers[i]; i++) {
                // G(n,k)=G(n,k-1)-f(p_k)(G(n/{p_k})-S_{k-1})
                int_t prev;
                int_t prevNum = numbers[i] / primes[k];
                if (prevNum <= sqrt) {
                    prev = hash0[prevNum];
                } else {
                    prev = hash1[n / prevNum];
                }
                // #ifdef DEBUG
                //             cout << "processing k = " << k << " aka " <<
                //             primes[k]
                //                  << " i = " << i << " aka " << numbers[i] <<
                //                  endl;
                //             cout << "i / k prev = " << prev << " aka " <<
                //             numbers[prev] << endl; cout << "substract g0 for " <<
                //             (g0[prev] - S0[k - 1]) << " prev "
                //                  << g0[prev] << " prime " << S0[k - 1] << endl;
                // #endif
                // k是阶段,i才是状态。
                g0[i] -= (g0[prev] - S0[k - 1]);
                g1[i] -= primes[k] * (g1[prev] - S1[k - 1]);
            }
        }
    #ifdef DEBUG
        cout << "g0 = " << g0[hash1[1]] << " g1 = " << g1[hash1[1]] << endl;
        int_t _g0 = 0, _g1 = 0;
        for (int_t i = 1; i <= n; i++) {
            if (isPrime[i]) {
                _g0 += 1;
                _g1 += i;
            }
        }
        cout << "_g0 = " << _g0 << " _g1 = " << _g1 << endl;
    #endif
        cout << Sphi(n, 1, sqrt, n) + 1 << " " << Smu(n, 1, sqrt, n) + 1 << endl;
    }
    
    int main() {
        init();
        int_t T;
        cin >> T;
        while (T--) {
            int_t n;
            cin >> n;
            process(n);
        }
        return 0;
    }

    exCRT

    #include <algorithm>
    #include <iostream>
    #include <tuple>
    #include <utility>
    using int_t = long long int;
    using lint_t = __int128_t;
    using std::cin;
    using std::cout;
    using std::endl;
    
    using pair_t = std::pair<int_t, int_t>;
    pair_t exgcd(int_t a, int_t b) {
        if (b == 0) return pair_t(1, 0);
        int_t x, y;
        std::tie(x, y) = exgcd(b, a % b);
        return pair_t(y, x - (lint_t)(a / b) * y);
    }
    int_t gcd(int_t a, int_t b) {
        if (b == 0) return a;
        return gcd(b, a % b);
    }
    //Ax+By=gcd(A,B) 不论什么情况下,x都可以对B/gcd(A,B)取模
    int_t solve(int_t* mods, int_t* coefs, int_t n) {
        int_t result = coefs[1], lcm = mods[1];
        for (int_t i = 2; i <= n; i++) {
            int_t mod = mods[i];
            int_t tx;
    #ifdef DEBUG
            cout << "joining " << coefs[i] << " mod " << mod << endl;
    #endif
            std::tie(tx, std::ignore) = exgcd(lcm, mod);
    #ifdef DEBUG
            cout << "raw tx = " << tx << " sx = " << sx << endl;
            cout << "to mod " << (mod / gcd(lcm, mod)) << endl;
    #endif
            tx = (tx % (mod / gcd(lcm, mod)) + (mod / gcd(lcm, mod))) %
                 (mod / gcd(lcm, mod));
            int_t C = ((coefs[i] - result) % mod + mod) % mod;
            int_t prod = C / gcd(lcm, mod);
    #ifdef DEBUG
            cout << "C = " << C << " prod = " << prod << endl;
            cout << "tx = " << tx << endl;
    #endif
            int_t D = mod / gcd(lcm, mod);
            //所有涉及乘法的地方都小心爆掉
            tx = ((lint_t)tx * prod % D + D) % D;
            int_t lcmx = lcm;
            lcm = (lint_t)lcm / gcd(lcm, mod) * mod;
            result = (result + (lint_t)lcmx * tx) % lcm;
    #ifdef DEBUG
            cout << "join " << i << " result = " << result << " lcm = " << lcm
                 << endl;
    #endif
        }
        return result;
    }
    int main() {
        const int_t LARGE = 1e5;
        static int_t mods[LARGE + 1], coefs[LARGE + 1];
        int_t n;
        scanf("%lld", &n);
        for (int_t i = 1; i <= n; i++) scanf("%lld%lld", &mods[i], &coefs[i]);
        printf("%lld", solve(mods, coefs, n));
    
        return 0;
    }

    Pollard Rho

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <inttypes.h>
    #include <random>
    #define debug(x) std::cout << #x << " = " << x << std::endl;
    
    typedef long long int int_t;
    
    using std::cin;
    using std::endl;
    using std::cout;
    std::mt19937 gen;
    int_t mul(int_t a,int_t b,int_t mod){
        return (__int128_t) a * b % mod;
    }
    int_t power(int_t base,int_t index,int_t mod){
        int_t result = 1;
        while(index){
            if(index & 1) result = mul(result,base,mod);
            index >>= 1;
            base = mul(base,base,mod);
        }
        return result;
    }
    bool isPrime(int_t p){
        if(p <= 1) return false;
        if(p == 2) return true;
        int_t s = 0,t = p - 1;
        while(t % 2 == 0) {
            t/=2;
            s+=1;
        }
        const int_t TRIAL_TIMES = 3;
        std::uniform_int_distribution<int_t> rand_int(2,p-1);
        for(int_t _ = 1; _ <= TRIAL_TIMES ;_ ++){
            int_t a = rand_int(gen);
            int_t prev = power(a,t,p);
            for(int_t i = 1;i <= s;i ++){
                int_t curr = mul(prev,prev,p);
                if(curr == 1 && prev != 1 && prev != p - 1) return false;
                prev = curr;
            }
            if(prev != 1) return false;
        }
        return true;
    }
    int_t gcd(int_t a,int_t b){
        if(b == 0) return a;
        return gcd(b,a%b);
    }
    int_t getFactor(int_t n,int_t c){
        const auto f = [=](int_t x)->int_t{
            return (mul(x,x,n) + c) % n;
        };
        std::uniform_int_distribution<int_t> rand_int(2,n-1);
        int_t x = rand_int(gen);
        int_t y = rand_int(gen);
        int_t k = 2,i = 0;
        int_t prod = 1,factor = 1;
        while(true){
            i ++;
            x = f(x);
            prod = mul(prod,std::abs(y - x),n);
            if(i % 256 == 0){
                factor = gcd(prod,n);
                if(factor > 1) return factor;
            }
            if(x == y) return n;
            if(i == k){
                i = 0;
                k *= 2;
                factor = std::max(factor,gcd(prod,n));
                if(factor > 1) return factor;
                prod = 1;
                y = x;
                
            }
        }
    }
    int_t pollardRho(int_t x){
        if(isPrime(x)) return x;
        std::uniform_int_distribution<int_t> rand_int(2,x-1);
        int_t c = rand_int(gen);
        int_t factor = x;
        while(factor == x){
            factor = getFactor(x,c --);
            if(c <= 2) c = gen();
        }
        return std::max(pollardRho(factor),pollardRho(x / factor));
    }
    int main() {
        gen.seed(std::random_device()());
        int_t T;
        cin >> T;
        while(T --){
            int_t x;
            cin >> x;
            if(isPrime(x)) cout << "Prime" << endl;
            else {
                cout << pollardRho(x) << endl;
            }
        }
        return 0;
    }

    01Trie

    可以代替用于维护集合的平衡树。

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <inttypes.h>
    #include <assert.h>
    #define debug(x) std::cout << #x << " = " << x << std::endl;
    
    typedef long long int int_t;
    
    using std::cin;
    using std::endl;
    using std::cout;
    const int_t BITS = 25;
    const int_t OFFSET = 1e7;
    struct Node {
    	Node* chds[2] = {nullptr,nullptr};
    	Node* parent = nullptr;
    	int_t size = 0;
    	int_t count = 0;
    	void maintain() {
    		size = count;
    		if(chds[0]) size += chds[0] -> size;
    		if(chds[1]) size += chds[1] -> size;
    	}
    	int_t leftSize() {
    		if(chds[0]) return chds[0] -> size;
    		return 0;
    	}
    };
    Node* root = new Node;
    void insert(Node* node,int_t val) {
    	for(int_t i = BITS - 1; i >= 0; i --) {
    		int_t bit = (val & (1 << i)) != 0;
    		auto& chd = node -> chds[bit];
    		if(chd == nullptr) {
    			chd = new Node;
    			chd -> parent = node;
    		}
    		node = chd;
    	}
    	node -> count += 1;
    	while(node) {
    		node -> maintain();
    		node = node -> parent;
    	}
    }
    void remove(Node* node,int_t val) {
    	for(int_t i = BITS - 1; i >= 0; i --) {
    		int_t bit = (val & (1 << i)) != 0;
    		auto& chd = node -> chds[bit];
    		node = chd;
    	}
    	node -> count -= 1;
    	while(node) {
    		node -> maintain();
    		node = node -> parent;
    	}
    }
    int_t rank(Node* node,int_t val) {
        insert(root,val);
    	int_t result = 1;
    	for(int_t i = BITS - 1; i >= 0; i --) {
    		int_t bit = (val & (1 << i)) != 0;
    		auto& chd = node -> chds[bit];
    		if(bit == 1 ) {
    		    result += node -> leftSize();
            }
    		node = chd;
    	}
    	remove(root,val);
        return result;
    }
    int_t kth(Node* node,int_t k) {
    	int_t result = 0;
    	for(int_t i = BITS - 1; i >= 0; i --) {
    		if(k <= node -> leftSize()) {
    			node = node -> chds[0];
    		} else {
    			result |= (1 << i);
    			k -= node -> leftSize();
    			node = node -> chds[1];
    		}
    	}
    	return result;
    }
    Node* locate(Node* node,int_t val) {
    	for(int_t i = BITS - 1; i >= 0; i --) {
    		int_t bit = (val & (1 << i)) != 0;
    		auto& chd = node -> chds[bit];
    		node = chd;
    	}
    	return node;
    }
    
    int n;
    int main() {
    	scanf("%d",&n);
    	while(n--) {
    		int_t opt,val;
    		scanf("%lld%lld",&opt,&val);
    		if(opt == 1) {
    			insert(root,val + OFFSET);
    		} else if(opt == 2) {
    			remove(root,val + OFFSET);
    		} else if(opt == 3) {
    			printf("%lld\n",rank(root,val + OFFSET));
    		} else if(opt == 4) {
    			printf("%lld\n",kth(root,val) - OFFSET);
    		} else if(opt == 5) {
    			int_t rank = ::rank(root,val + OFFSET) - 1;
    			printf("%lld\n",kth(root,rank) - OFFSET);
    		} else if(opt == 6) {
    			int_t rank = ::rank(root,val + OFFSET);
    			int_t count = locate(root,val + OFFSET) -> count;
    			printf("%lld\n",kth(root,rank + count ) - OFFSET);
    		}
    	}
    	return 0;
    }

    匈牙利

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <inttypes.h>
    #include <cstring>
    #define debug(x) std::cout << #x << " = " << x << std::endl;
    
    typedef long long int int_t;
    
    using std::cin;
    using std::endl;
    using std::cout;
    
    const int_t LARGE = 1000;
    
    std::vector<int_t> graph[LARGE + 1];
    
    int_t lmatch[LARGE + 1],rmatch[LARGE + 1];
    bool visited[LARGE + 1];
    bool DFS(int_t vtx){
        for(int_t to : graph[vtx]){
            if(visited[to]) continue;
            visited[to] = true;
            if(rmatch[to] == -1 || DFS(rmatch[to])){
                rmatch[to] = vtx;
                lmatch[vtx] = to;
                return true;
            }
        }
        return false;
    }
    int_t n,m,e;
    int main() {
        cin >> n >> m >> e;
        for(int_t i = 1;i <= e;i ++){
            int_t left,right;
            cin >> left >> right;
            if(right > m || left > n) continue;
            graph[left].push_back(right);
        }
        memset(lmatch,-1,sizeof(lmatch));
        memset(rmatch,-1,sizeof(rmatch));
        int_t result = 0;
        for(int_t i = 1;i <= n;i ++){
            if(lmatch[i] == -1){
                memset(visited,0,sizeof(visited));
                if(DFS(i)) result++;
            }
        }
        cout << result << endl;
        return 0;
    }

    KDTree

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <inttypes.h>
    #include <utility>
    #define debug(x) std::cout << #x << " = " << x << std::endl;
    
    typedef long long int int_t;
    
    using std::cin;
    using std::endl;
    using std::cout;
    const int_t X = 0;
    const int_t Y = 1;
    const auto COEF = 0.75;
    
    struct Point {
    	int_t pos[2];
    	Point(int_t x=0,int_t y=0) {
    		this->pos[X]=x;
    		this->pos[Y]=y;
    	}
    	int_t& operator[](int_t v) {
    		return pos[v];
    	}
    };
    struct Node {
    	Node* left = nullptr,* right = nullptr;
    	Point LD,RU;
    	Point point;
    	int_t value = 0;
    	int_t sum = 0;
    	int_t size = 0;
    	Node(Point point,int_t value) {
    		this -> point = point;
    		this -> value = value;
    		maintain();
    	}
    	int_t maxSize() {
    		int_t size = 0;
    		if(left) size = std::max(left -> size,size);
    		if(right) size = std::max(right -> size,size);
    		return size;
    	}
    	void updateFrom(Node* node) {
    		LD[X]=std::min(node->LD[X],LD[X]);
    		LD[Y]=std::min(node->LD[Y],LD[Y]);
    		RU[X]=std::max(node->RU[X],RU[X]);
    		RU[Y]=std::max(node->RU[Y],RU[Y]);
    		sum += node -> sum;
    		size += node -> size;
    	}
    	void maintain() {
    		LD = RU = point;
    		sum = value;
    		size = 1;
    		if(left) updateFrom(left);
    		if(right) updateFrom(right);
    	}
    	int_t query(const Point& LD,const Point& RU) {
    		//ÍêÈ«°üº¬
    		if(this -> LD[X] >= LD.pos[X] && this -> LD[Y] >= LD.pos[Y] && this -> RU[X] <= RU.pos[X] && this -> RU[Y] <= RU.pos[Y]) {
    			return this -> sum;
    		}
    		//ÍêÈ«²»°üº¬
    		if(RU.pos[X] < this -> LD.pos[X] || RU.pos[Y] < this -> LD.pos[Y] || LD.pos[X] > this -> RU.pos[X] || LD.pos[Y] > this -> RU.pos[Y]) return 0;
    		int_t sum = 0;
    		if(this->point[X] >= LD.pos[X] && this -> point[X] <= RU.pos[X] && this -> point[Y] >= LD.pos[Y] && this -> point[Y] <= RU.pos[Y]) sum += this -> value;
    		if(left) sum += left -> query(LD,RU);
    		if(right) sum += right -> query(LD,RU);
    		return sum;
    	}
    };
    using pair_t = std::pair<Point,int_t>;
    Node* build(pair_t* left,pair_t* right,int_t dir = 0) {
    	if(left > right) return nullptr;
    	pair_t* mid = left + (right - left + 1) / 2;
    	std::nth_element(left,mid,right + 1,[=](const pair_t& a,const pair_t& b) {
    		return a.first.pos[dir] < b.first.pos[dir];
    	});
    	Node* node = new Node(mid -> first,mid -> second);
    	node -> left = build(left,mid-1,dir ^ 1);
    	node -> right = build(mid + 1,right,dir ^ 1);
    	node -> maintain();
    	return node;
    }
    void walk(Node* root,std::vector<pair_t> & output) {
    	if(root==nullptr) return;
    	walk(root -> left,output);
    	Node* right = root -> right;
    	output.push_back(pair_t(root -> point,root -> value));
    	delete root;
    	walk(right,output);
    }
    Node* rebuild(Node* root,int_t dir) {
    	std::vector<pair_t> output;
    	walk(root,output);
    	Node* result = build(&output[0],&output.back(),dir);
    	return result;
    }
    
    Node* insert(Node* root,const Point& point,int_t value,int_t dir = 0) {
    	if(root == nullptr) {
    		return new Node(point,value);
    	}
    	if(point.pos[dir] < root->point[dir]) {
    		root -> left = insert(root -> left,point,value,dir ^ 1);
    	} else {
    		root -> right = insert(root -> right,point,value,dir ^ 1);
    	}
    	root -> maintain();
    	if((double)root -> maxSize() / root -> size >  COEF) {
    
    		root = rebuild(root,dir);
    	}
    	return root;
    }
    int main() {
    	int_t n;
    	cin >> n;
    	int_t lastans = 0;
    	Node* root = nullptr;
    	while(true) {
    		int opt;
    		scanf("%d",&opt);
    		if(opt == 1) {
    			int_t x,y,val;
    			scanf("%lld%lld%lld",&x,&y,&val);
    			x^=lastans;
    			y^=lastans;
    			val^=lastans;
    			root = insert(root,Point(x,y),val);
    		} else if(opt == 2) {
    			int_t x1,y1,x2,y2;
    			scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
    			x1^=lastans;
    			x2^=lastans;
    			y1^=lastans;
    			y2^=lastans;
    			if(root == nullptr) lastans = 0;
    			else lastans = root -> query(Point(x1,y1),Point(x2,y2));
    			printf("%lld\n",lastans);
    		}else if(opt==3){
    		    break;
            }
    	}
    	return 0;
    }

     

  • 洛谷3792 由乃与大母神原型和偶像崇拜

    一个区间可以重排称为连续段,当且仅当

    • 区间最大值-区间最小值=区间长度
    • 区间内没有重复的数

    对于第一个条件显然很好维护(线段树查询区间最值),对于第二个条件,我们给每个出现的数映射到一个随机的权值。

    然后对于查询区间$[left,right]$,我们查询出这个区间内所有数的异或值,然后将其与从$MIN_{left\leq i\leq right}a_i$到$MAX_{left\leq i\leq right}a_i$的数的权值异或起来进行对比,如果相等则可以认为这个区间没有重复的数。

    #include <assert.h>
    #include <algorithm>
    #include <cstring>
    #include <ctime>
    #include <iostream>
    #include <random>
    #include <tuple>
    #include <utility>
    using int_t = long long int;
    using pair_t = std::pair<int_t, int_t>;
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int_t LARGE = 1 << 20;
    const int_t INF = 0x7fffffff;
    std::mt19937 gen;
    std::uniform_int_distribution<int_t> rand_int(0, INT64_MAX);
    int_t xorVal[LARGE + 1];
    int_t maxVal[LARGE + 1], minVal[LARGE + 1];
    int_t offset;
    void init(int_t n) {
        n += 2;
        offset = 1;
        while (offset < n) offset *= 2;
        memset(minVal, 0x3f, sizeof(minVal));
        // memcpy(xors,)
    }
    
    int_t queryXor(int_t left, int_t right) {
        left += offset - 1;
        right += offset + 1;
        int_t result = 0;
        while ((left ^ right) != 1) {
            if ((left & 1) == 0) result ^= xorVal[left ^ 1];
            if ((right & 1)) result ^= xorVal[right ^ 1];
            left /= 2;
            right /= 2;
        }
        return result;
    }
    pair_t queryMaxMin(int_t left, int_t right) {
        left += offset - 1;
        right += offset + 1;
        int_t max = 0, min = INF;
        while ((left ^ right) != 1) {
            if ((left & 1) == 0) {
                max = std::max(max, maxVal[left ^ 1]);
                min = std::min(min, minVal[left ^ 1]);
            };
            if ((right & 1)) {
                max = std::max(max, maxVal[right ^ 1]);
                min = std::min(min, minVal[right ^ 1]);
            }
            left /= 2;
            right /= 2;
        }
        return pair_t(max, min);
    }
    void modifyXor(int_t pos, int_t val) {
        pos += offset;
        xorVal[pos] = val;
        pos /= 2;
        while (pos) {
            xorVal[pos] = xorVal[pos * 2 + 1] ^ xorVal[pos * 2];
            pos /= 2;
        }
    }
    void modifyVal(int_t pos, int_t val) {
        pos += offset;
        minVal[pos] = maxVal[pos] = val;
        pos /= 2;
        while (pos) {
            minVal[pos] = std::min(minVal[pos * 2], minVal[pos * 2 + 1]);
            maxVal[pos] = std::max(maxVal[pos * 2], maxVal[pos * 2 + 1]);
            pos /= 2;
        }
    }
    struct Opt {
        int_t v1, v2;
        int_t type;
    } opts[LARGE + 1];
    int_t n, m;
    std::vector<int_t> numbers;
    int_t prefix[LARGE + 1];
    int_t getRank(int_t x) {
        return std::lower_bound(numbers.begin(), numbers.end(), x) -
               numbers.begin() + 1;
    }
    int_t nums[LARGE + 1];
    int main() {
        gen.seed(std::random_device()() + int_t(new char) + time(0));
        scanf("%lld%lld", &n, &m);
        init(n);
        for (int_t i = 1; i <= n; i++) {
            scanf("%lld", &nums[i]);
            numbers.push_back(nums[i]);
            numbers.push_back(nums[i] + 1);
        }
        for (int_t i = 1; i <= m; i++) {
            auto& opt = opts[i];
            scanf("%lld%lld%lld", &opt.type, &opt.v1, &opt.v2);
            if (opt.type == 1) {
                numbers.push_back(opt.v2);
                numbers.push_back(opt.v2 + 1);
            }
        }
        std::sort(numbers.begin(), numbers.end());
        numbers.resize(std::unique(numbers.begin(), numbers.end()) -
                       numbers.begin());
        for (int_t i = 1; i <= numbers.size(); i++) {
            int_t val = rand_int(gen);
            prefix[i] = prefix[i - 1] ^ val;
        }
        for (int_t i = 1; i <= n; i++) {
            int_t curr = getRank(nums[i]);
            modifyXor(i, prefix[curr] ^ prefix[curr - 1]);
            modifyVal(i, curr);
        }
        for (int_t i = 1; i <= m; i++) {
            const auto& opt = opts[i];
            if (opt.type == 1) {
                int_t numbers = getRank(opt.v2);
                modifyVal(opt.v1, numbers);
                //离散化和没离散化的搞混了
                modifyXor(opt.v1, prefix[numbers] ^ prefix[numbers - 1]);
            } else {
                int_t min, max;
                std::tie(max, min) = queryMaxMin(opt.v1, opt.v2);
                //区间长度必须要等于max-min+1!
                if (max - min == opt.v2 - opt.v1 &&
                    (prefix[max] ^ prefix[min - 1]) == queryXor(opt.v1, opt.v2)) {
                    printf("damushen\n");
                } else {
                    printf("yuanxing\n");
                }
            }
        }
        return 0;
    }

     

  • 多项式反三角函数

    $$ \text{由欧拉公式得}e^{i\theta}=\cos \left( \theta \right) +i\sin \left( \theta \right) \\ e^{-i\theta}=\cos \left( \theta \right) -i\sin \left( \theta \right) \\ \text{故}\sin \left( \theta \right) =\frac{e^{i\theta}-e^{-i\theta}}{2i} \\ \text{设}\sin \left( \theta \right) =x,\arcsin \left( x \right) =\theta \\ \text{设}y=e^{i\theta} \\ \text{则}x=\frac{y-\frac{1}{y}}{2i} \\ 2ix=y-\frac{1}{y} \\ y^2-2ixy-1=0 \\ y=\frac{2ix\pm \sqrt{-4x^2+4}}{2}=\frac{2ix\pm 2\sqrt{1-x^2}}{2}=ix\pm \sqrt{1-x^2} \\ \text{令}\theta =\text{0,可得}x=\text{0,}y=\text{1,故}y=ix+\sqrt{1-x^2} \\ \text{所以}e^{i\theta}=ix+\sqrt{1-x^2} \\ i\theta =\log \left( ix+\sqrt{1-x^2} \right) \\ \theta =\arcsin \left( x \right) =\frac{1}{i}\log \left( ix+\sqrt{1-x^2} \right) =-i\log \left( ix+\sqrt{1-x^2} \right) \\ \arcsin \left( F\left( x \right) \right) =-i\log \left( iF\left( x \right) +\sqrt{1-F\left( x \right) ^2} \right) \\ \cos \left( \theta \right) =\frac{e^{i\theta}+e^{-i\theta}}{2} \\ \text{同上可证}\arccos \left( x \right) =-i\log \left( x\pm \sqrt{x^2-1} \right) \\ \text{同上可证}\arctan \left( x \right) =\frac{i}{2}\log \left( \frac{1-iz}{1+iz} \right) $$

    #include <assert.h>
    #include <cmath>
    #include <cstring>
    #include <iostream>
    using int_t = long long int;
    
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int_t mod = 998244353;
    const int_t g = 3;
    const int_t LARGE = 1 << 19;
    template <typename T>
    T power(T base, int_t index);
    void poly_inv(const struct complex* A, int_t n, struct complex* result);
    int_t bitRev(int_t base, int_t size2);
    int_t upper2n(int_t x);
    void poly_log(const struct complex* A, int_t n, struct complex* result);
    void transform(complex* A, int_t len, int_t arg);
    void poly_exp(const struct complex* A, int_t n, struct complex* result);
    void poly_sqrt(const struct complex* A, int_t n, struct complex* result);
    struct complex {
        int_t real, imag;
        complex operator+(const complex& another) const {
            return complex{(real + another.real) % mod,
                           (imag + another.imag) % mod};
        }
        complex operator-(const complex& another) const {
            return complex{(real - another.real + mod) % mod,
                           (imag - another.imag + mod) % mod};
        }
        complex operator*(const complex& another) const {
            return complex{
                (real * another.real % mod - imag * another.imag % mod + mod) % mod,
                (real * another.imag % mod + imag * another.real % mod) % mod};
        }
        complex operator/(const complex& another) const {
            int_t a = real, b = imag, c = another.real, d = another.imag;
            int_t inv = power(c * c % mod + d * d % mod, -1);
            return complex{(a * c % mod + b * d % mod) % mod * inv % mod,
                           (b * c % mod - a * d % mod + mod) % mod * inv % mod};
        }
        complex operator%(const int_t& x) const {
            return complex{real % x, imag % x};
        }
        complex(int_t a = 0, int_t b = 0) {
            this->real = a;
            this->imag = b;
        }
        complex& operator=(const int_t& rhs) {
            this->real = rhs;
            this->imag = 0;
            return *this;
        }
    };
    std::ostream& operator<<(std::ostream& os, const complex& comp) {
        os << "complex{real=" << comp.real << ",imag=" << comp.imag << "}";
        return os;
    }
    int revs[20][LARGE + 1];
    
    int main() {
        for (int i = 0; (1 << i) <= LARGE; i++) {
            for (int j = 0; j < LARGE; j++) {
                revs[i][j] = bitRev(j, i);
            }
        }
        static complex A[LARGE], Ax[LARGE], B[LARGE];
        int_t n, type;
        scanf("%lld%lld", &n, &type);
        if (type == 0) {
            for (int_t i = 0; i < n; i++) {
                scanf("%lld", &A[i].real);
                Ax[i] = A[i];
            }
            int_t size2 = upper2n(n + n);
            transform(A, size2, 1);
            for (int_t i = 0; i < size2; i++) A[i] = A[i] * A[i];
            transform(A, size2, -1);
            const auto inv = complex{1, 0} / complex{size2, 0};
            for (int_t i = 0; i < size2; i++) {
                if (i < n)
                    A[i] = A[i] * inv;
                else
                    A[i] = 0;
            }
            A[0].real = 1;
            for (int_t i = 1; i < n; i++) A[i] = A[i] * complex{mod - 1, 0};
            poly_sqrt(A, n, B);
            for (int_t i = 0; i < n; i++) B[i] = B[i] + Ax[i] * complex{0, 1};
            memset(A, 0, sizeof(A));
            poly_log(B, n, A);
            for (int_t i = 0; i < n; i++) {
                A[i] = A[i] * complex{0, mod - 1};
            }
            for (int_t i = 0; i < n; i++) {
                printf("%lld ", A[i].real);
            }
        } else {
            for (int_t i = 0; i < n; i++) {
                int_t x;
                scanf("%lld", &x);
                A[i].imag = (mod - x) % mod;
                Ax[i].imag = x % mod;
            }
            Ax[0].real = A[0].real = 1;
            poly_inv(Ax, n, B);
            int_t size2 = upper2n(2 * n);
            transform(B, size2, 1);
            transform(A, size2, 1);
            for (int_t i = 0; i < size2; i++) B[i] = A[i] * B[i];
            transform(B, size2, -1);
            for (int_t i = 0; i < size2; i++) {
                if (i < n)
                    B[i] = B[i] / complex{size2, 0};
                else
                    B[i] = 0;
            }
            memset(A, 0, sizeof(A));
            poly_log(B, n, A);
            for (int_t i = 0; i < n; i++) {
                A[i] = A[i] / complex{2, 0} * complex{0, 1};
                printf("%lld ", A[i].real);
            }
        }
        return 0;
    }
    
    void transform(complex* A, int_t len, int_t arg) {
        int_t size2 = log2(len);
        for (int_t i = 0; i < len; i++) {
            int_t x = revs[size2][i];
            if (x > i) std::swap(A[i], A[x]);
        }
        for (int_t i = 2; i <= len; i *= 2) {
            complex mr = power(complex{g, 0}, arg * (mod - 1) / i);
            for (int_t j = 0; j < len; j += i) {
                complex curr{1, 0};
                for (int_t k = 0; k < i / 2; k++) {
                    complex u = A[j + k];
                    complex t = A[j + k + i / 2] * curr;
                    A[j + k] = (u + t);
                    A[j + k + i / 2] = (u - t);
                    curr = curr * mr;
                }
            }
        }
    }
    //计算多项式A在模x^n下的逆元
    // C(x)<-2B(x)-A(x)B^2(x)
    void poly_inv(const complex* A, int_t n, complex* result) {
        if (n == 1) {
            result[0] = power(A[0], -1);
            return;
        }
        poly_inv(A, n / 2 + n % 2, result);
        static complex temp[LARGE + 1];
        int_t size2 = upper2n(3 * n + 1);
        for (int_t i = 0; i < size2; i++) {
            if (i < n)
                temp[i] = A[i];
            else
                temp[i] = complex{0, 0};
        }
        transform(temp, size2, 1);
        transform(result, size2, 1);
        for (int_t i = 0; i < size2; i++) {
            result[i] =
                (complex{2, 0} * result[i] - temp[i] * result[i] * result[i]);
        }
        transform(result, size2, -1);
        int_t inv = power(size2, -1);
        for (int_t i = 0; i < size2; i++) {
            if (i < n) {
                result[i] = result[i] * complex{inv, 0};
            } else {
                result[i] = complex{0, 0};
            }
        }
    }
    
    void poly_log(const complex* A, int_t n, complex* result) {
        int_t size2 = upper2n(2 * n);
        static complex Ad[LARGE + 1];
        for (int_t i = 0; i < size2; i++) {
            if (i < n) {
                Ad[i] = complex{(i + 1), 0} * A[i + 1];
    
            } else {
                Ad[i] = complex{0, 0};
            }
            result[i] = complex{0, 0};
        }
        transform(Ad, size2, 1);
        poly_inv(A, n, result);
        transform(result, size2, 1);
        for (int_t i = 0; i < size2; i++) {
            result[i] = result[i] * Ad[i];
        }
        transform(result, size2, -1);
        int_t inv = power(size2, -1);
        for (int_t i = 0; i < size2; i++)
            if (i < n)
                result[i] = result[i] * complex{inv, 0};
            else
                result[i] = complex{0, 0};
        for (int_t i = n - 1; i >= 1; i--) {
            result[i] = result[i - 1] / complex{i, 0};
        }
        result[0] = complex{0, 0};
    }
    void poly_exp(const complex* A, int_t n, complex* result) {
        if (n == 1) {
            // assert(A[0] == 0);
            result[0] = complex{1, 0};
            return;
        }
        poly_exp(A, n / 2 + n % 2, result);
        static complex G0[LARGE + 1], Ax[LARGE + 1];
        int_t size2 = upper2n(2 * n);
        poly_log(result, n, G0);
        for (int_t i = 0; i < size2; i++) {
            if (i < n)
                Ax[i] = A[i];
            else
                Ax[i] = complex{0, 0};
        }
        transform(Ax, size2, 1);
        transform(G0, size2, 1);
        transform(result, size2, 1);
        for (int_t i = 0; i < size2; i++)
            result[i] = (result[i] - result[i] * (G0[i] - Ax[i]));
        transform(result, size2, -1);
        int_t inv = power(size2, -1);
        for (int_t i = 0; i < size2; i++)
            if (i < n)
                result[i] = result[i] * complex{inv, 0};
            else
                result[i] = complex{0, 0};
    }
    void poly_sqrt(const complex* A, int_t n, complex* result) {
        if (n == 1) {
            assert(A[0].real <= 1);
            result[0] = A[0];
            return;
        }
        poly_sqrt(A, n / 2 + n % 2, result);
        int_t size2 = upper2n(3 * n);
        static complex Ax[LARGE + 1], pInv[LARGE];
        for (int_t i = 0; i < size2; i++) {
            if (i < n) {
                Ax[i] = A[i];
            } else {
                Ax[i] = 0;
            }
            pInv[i] = 0;
        }
        poly_inv(result, n, pInv);
        transform(Ax, size2, 1);
        transform(result, size2, 1);
        transform(pInv, size2, 1);
        const int_t inv2 = power(2ll, -1);
        for (int_t i = 0; i < size2; i++) {
            result[i] = (result[i] -
                         (result[i] * result[i] % mod - Ax[i] + mod) % mod * inv2 %
                             mod * pInv[i] % mod +
                         mod) %
                        mod;
        }
        transform(result, size2, -1);
        for (int_t i = 0; i < size2; i++) {
            if (i < n)
                result[i] = result[i] * power(size2, -1) % mod;
            else
                result[i] = 0;
        }
    }
    template <typename T>
    T power(T base, int_t index) {
        const int_t phi = mod - 1;
        index = (index % phi + phi) % phi;
        T result = 1;
        while (index) {
            if (index & 1) result = result * base % mod;
            base = base * base % mod;
            index >>= 1;
        }
        return result;
    }
    int_t bitRev(int_t base, int_t size2) {
        int_t result = 0;
        for (int_t i = 1; i < size2; i++) {
            result |= (base & 1);
            base >>= 1;
            result <<= 1;
        }
        result |= (base & 1);
        return result;
    }
    int_t upper2n(int_t x) {
        int_t result = 1;
        while (result < x) result *= 2;
        return result;
    }

     

  • 雅礼集训Day10 T3 加农炮

    好好看文件名!!!

    直接在Stern Brocot树上走,每次走到一个点,通过类欧几里得求出来这个斜率的直线左侧的整点个数。

    然后二分在Stern Brocot树上向左或者向右跳。

    复杂度$O(Tlog^3n)$

    $$ \text{求}\frac{x}{y}<\frac{a}{b},x\in \left[ \text{1,}n \right] \cap \text{Z,}y\in \left[ \text{1,}m \right] \cap \text{Z的}\frac{x}{y}\text{个数。} \\ \text{式子变形得到} \\ x<\frac{ay}{b} \\ xb<ay \\ \text{考虑直接枚举}x,\text{则可得}\sum_{1\le x\le n}{\sum_{1\le y\le m}{\left[ y>\frac{bx}{a} \right]}} \\ =\sum_{1\le x\le n}{\sum_{1\le y\le m}{\left[ y>\lfloor \frac{bx}{a} \rfloor \right]}} \\ =\sum_{1\le x\le n}{\left( m-\lfloor \frac{bx}{a} \rfloor \right) \left[ m>\lfloor \frac{bx}{a} \rfloor \right]} \\ \text{由}m>\lfloor \frac{bx}{a} \rfloor \text{可得}m>\frac{bx}{a}\text{,进而}ma>bx \\ \text{可得}x<\frac{ma}{b},\text{即}x<\lceil \frac{ma}{b} \rceil ,\text{即}x\le \lceil \frac{ma}{b} \rceil -1 \\ \text{故原式等价于}\sum_{1\le x\le \min \left( n,\lceil \frac{ma}{b} \rceil -1 \right)}{m-\lfloor \frac{bx}{a} \rfloor} \\ =m\times \min \left( n,\lceil \frac{ma}{b} \rceil -1 \right) -\sum_{1\le x\le \min \left( n,\lceil \frac{ma}{b} \rceil -1 \right)}{\lfloor \frac{bx}{a} \rfloor} \\ \text{考虑如何计算}f\left( n,a,b,c \right) =\sum_{0\le i\le n}{\lfloor \frac{ai+b}{c} \rfloor} \\ f\left( n,a,b,c \right) =\sum_{0\le i\le n}{\sum_{0\le j\le \lfloor \frac{ai+b}{c} \rfloor -1}{1}} \\ =\sum_{0\le i\le n}{\sum_{0\le j\le \lfloor \frac{an+b}{c} \rfloor -1}{\left[ j<\lfloor \frac{ai+b}{c} \rfloor \right]}} \\ =\sum_{0\le j\le \lfloor \frac{an+b}{c} \rfloor -1}{\sum_{0\le i\le n}{\left[ j<\lfloor \frac{ai+b}{c} \rfloor \right]}} \\ \text{由于}\lfloor \frac{ai+b}{c} \rfloor =\lceil \frac{ai+b-c+1}{c} \rceil \\ \left( \begin{array}{c} \text{证明直接考虑:对于}\frac{an+b}{c}\text{为非整数时,}\\ \lfloor \frac{an+b}{c} \rfloor =\lceil \frac{an+b}{c}-1 \rceil =\lceil \frac{an+b-c}{c} \rceil \text{成立,对于整数,加上修正值}\frac{1}{c}\text{即可}\\ \end{array} \right) \\ \text{原式}=\sum_{0\le j\le \lfloor \frac{an+b}{c} \rfloor -1}{\sum_{0\le i\le n}{\left[ j<\lceil \frac{ai+b-c+1}{c} \rceil \right]}} \\ \text{又因为当}a<\lceil \frac{b}{c} \rceil \text{时,有}ac<b \\ \text{原式}=\sum_{0\le j\le \lfloor \frac{an+b}{c} \rfloor -1}{\sum_{0\le i\le n}{\left[ jc<ai+b-c+1 \right]}} \\ =\sum_{0\le j\le \lfloor \frac{an+b}{c} \rfloor -1}{\sum_{0\le i\le n}{\left[ ai>jc-b+c-1 \right]}} \\ =\sum_{0\le j\le \lfloor \frac{an+b}{c} \rfloor -1}{\sum_{0\le i\le n}{\left[ i\ge \lfloor \frac{jc-b+c-1}{a} \rfloor \right]}} \\ =\sum_{0\le j\le \lfloor \frac{an+b}{c} \rfloor -1}{n-\sum_{0\le i\le n}{\left[ i<\lfloor \frac{jc-b+c-1}{a} \rfloor \right]}} \\ =n\times \left( \lfloor \frac{an+b}{c} \rfloor \right) -\sum_{0\le j\le \lfloor \frac{an+b}{c} \rfloor -1}{\lfloor \frac{jc-b+c-1}{a} \rfloor} \\ =n\times \left( \lfloor \frac{an+b}{c} \rfloor \right) -f\left( \lfloor \frac{an+b}{c} \rfloor -\text{1,}c,-b+c-\text{1,}a \right) \\ \text{边界条件:} \\ f\left( \text{0,}a,b,c \right) =\lfloor \frac{b}{c} \rfloor \\ f\left( n,a,b,c \right) \left( a\ge c\text{或}b\ge c \right) =\sum_{0\le i\le n}{\lfloor \frac{ai+b}{c} \rfloor} \\ =\sum_{0\le i\le n}{\lfloor \frac{ai}{c}+\frac{b}{c} \rfloor} \\ =\sum_{0\le i\le n}{\lfloor \left( \lfloor \frac{a}{c} \rfloor +\frac{a-c\lfloor \frac{a}{c} \rfloor}{c} \right) i+\lfloor \frac{b}{c} \rfloor +\frac{b-c\lfloor \frac{b}{c} \rfloor}{c} \rfloor} \\ =\sum_{0\le i\le n}{\lfloor \frac{\left( a\,\,\text{mod }c \right) i+b\,\,\text{mod }c}{c} \rfloor +i\lfloor \frac{a}{c} \rfloor +\lfloor \frac{b}{c} \rfloor} \\ =\frac{n\left( n+1 \right)}{2}\lfloor \frac{a}{c} \rfloor +\lfloor \frac{b}{c} \rfloor \left( n+1 \right) +\sum_{0\le i\le n}{\lfloor \frac{\left( a\,\,\text{mod }c \right) i+b\,\,\text{mod }c}{c} \rfloor} \\ =\frac{n\left( n+1 \right)}{2}\lfloor \frac{a}{c} \rfloor +\lfloor \frac{b}{c} \rfloor \left( n+1 \right) +f\left( n,a\,\,\text{mod }c,b\,\,\text{mod }c,c \right) \\ \text{复杂度}O\left( \log N \right) $$

    #include <assert.h>
    #include <algorithm>
    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    #include <vector>
    
    using int_t = long long int;
    using std::cin;
    using std::cout;
    using std::endl;
    int_t n, m;
    struct Result {
        int_t x, y, pos;
    };
    
    int_t gcd(int_t a, int_t b) {
        if (b == 0) return a;
        return gcd(b, a % b);
    }
    //��ȡб��Ϊy/x��ֱ���������ڵ��������
    int_t getCountOnLine(int_t x, int_t y, int_t n, int_t m) {
        return std::min(n / x, m / y);
    }
    int_t fx(int_t n, int_t a, int_t b, int_t c) {
        if (n < 0) return 0;
        if (n == 0) return b / c;
        if (a >= c || b >= c) {
            return fx(n, a % c, b % c, c) + (n * (n + 1) / 2 * (a / c)) +
                   (n + 1) * (b / c);
        } else {
            if (a == 0)
                return 0;
            else {
                return n * ((a * n + b) / c) -
                       fx((a * n + b) / c - 1, c, c - b - 1, a);
            }
        }
    }
    // x��1��n�ڣ�y��1��m�ڣ�������a/b�ķ�������
    int_t getCount(int_t a, int_t b, int_t n, int_t m) {
        int_t d = (m * a) / b + ((m * a) % b != 0);
        int_t c = std::min(n, d - 1);
        int_t result = c * m - (fx(c, b, 0, a)) + getCountOnLine(a, b, n, m);
        return result;
    }
    Result walk(int_t n, int_t m, int_t k) {
        const auto check = [&](int_t a, int_t b) -> int_t {
            //���Ϸ�
            if (a > n || b > m) return 2;
            int_t under = getCount(a, b, n, m);
            int_t line = getCountOnLine(a, b, n, m);
            // a/b��С
            if (k > under) return -1;
            // a/b����
            else if (k < under - line + 1)
                return 1;
            else
                return 0;
        };
        //��ǰ������Ҳ�ķ���
        int_t leftA = 0, leftB = 1, rightA = 1, rightB = 0;
        int_t A, B;
        while (true) {
            int_t nextA = leftA + rightA;
            int_t nextB = leftB + rightB;
            int_t x = check(nextA, nextB);
            if (x == 0) {
                A = nextA;
                B = nextB;
                break;
            }
            int_t left = 1, right = n;
            int_t result = 0;
            //���ұ�������
            if (x < 0) {
                while (left <= right) {
                    int_t mid = (left + right) / 2;
                    if (check(leftA + mid * rightA, leftB + mid * rightB) < 0) {
                        left = mid + 1;
                        result = mid;
                    } else {
                        right = mid - 1;
                    }
                }
                leftA += result * rightA;
                leftB += result * rightB;
    
            } else {
                //������
                while (left <= right) {
                    int_t mid = (left + right) / 2;
                    if (check(rightA + mid * leftA, rightB + mid * leftB) == 1) {
                        left = mid + 1;
                        result = mid;
                    } else {
                        right = mid - 1;
                    }
                }
                rightA += result * leftA;
                rightB += result * leftB;
            }
        }
        int_t under = getCount(A, B, n, m) - getCountOnLine(A, B, n, m);
        k -= under;
        return Result{A * k, B * k};
    }
    void query(int_t n, int_t m, int_t k) {
        if (k <= m - 1) {
            printf("%lld %lld\n", 1ll, k + 1);
        } else if (k > (n * (m - 1))) {
            printf("%lld %lld\n", k - (n * (m - 1)) + 1, 1ll);
        } else {
            auto result = walk(n - 1, m - 1, k - (m - 1));
            printf("%lld %lld\n", result.x + 1, result.y + 1);
        }
    }
    int main() {
        // while (true) {
        //     int_t a, b, n, m;
        //     cin >> a >> b >> n >> m;
        //     cout << getCount(a, b, n, m) << endl;
        // }
        int T;
        scanf("%d", &T);
        while (T--) {
            int_t n, m, k;
            scanf("%lld%lld%lld", &n, &m, &k);
            query(n, m, k);
        }
    
        return 0;
    }

     

  • 雅礼集训D4T2 gre

    很毒瘤。

    考虑递归构造。

    首先k=1的时候,答案为a。

    增加k时,将现有字符串中的字符全部顺移一位(aabaa变成bbcbb)

    然后新字符串先放两个a,然后遍历旧字符串,每次遇到一个b就放ba,直到放完,然后再放一个a。

    最后把不到n的部分拿a补上。

    #include <assert.h>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <map>
    #include <vector>
    using int_t = long long int;
    using std::cerr;
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int_t LARGE = 1e5;
    
    void process() {
        int_t n, k;
        cin >> n >> k;
        std::vector<char> buf;
        buf.push_back('a');
        for (int_t i = 1; i <= k - 1; i++) {
            std::vector<char> next{'a', 'a'};
            for (char chr : buf) {
                next.push_back(chr + 1);
                if (chr == 'a') {
                    next.push_back('a');
                }
            }
            next.push_back('a');
            buf = next;
        }
    #ifdef DEBUG
        for (char chr : buf) cout << chr << " ";
        cout << endl;
    #endif
        if (n < buf.size()) {
            printf("CiYe\n");
            return;
        }
        for (int_t i = 1; i <= n - buf.size(); i++) {
            printf("a");
        }
        for (char chr : buf) printf("%c", chr);
        cout << endl;
    }
    
    int main() {
        int_t T;
        cin >> T;
        while (T--) {
            process();
        }
    
        return 0;
    }