1286D - LCC - CodeForces Solution


data structures math matrices probabilities *3100

Please click on ads to support us..

C++ Code:

#include <algorithm>
#include <cassert>
#include <iostream>
#include <limits>
#include <vector>
using namespace std;

namespace IO {
    const int BUFFER_SIZE = 1 << 15;

    char input_buffer[BUFFER_SIZE];
    int input_pos = 0, input_len = 0;

    void _update_input_buffer() {
        input_len = fread(input_buffer, sizeof(char), BUFFER_SIZE, stdin);
        input_pos = 0;

        if (input_len == 0)
            input_buffer[0] = EOF;
    }

    inline char next_char(bool advance = true) {
        if (input_pos >= input_len)
            _update_input_buffer();

        return input_buffer[advance ? input_pos++ : input_pos];
    }

    template<typename T>
    inline void read_int(T &number) {
        bool negative = false;
        number = 0;

        while (!isdigit(next_char(false)))
            if (next_char() == '-')
                negative = true;

        do {
            number = 10 * number + (next_char() - '0');
        } while (isdigit(next_char(false)));

        if (negative)
            number = -number;
    }

    template<typename T, typename... Args>
    inline void read_int(T &number, Args &... args) {
        read_int(number);
        read_int(args...);
    }
}

const int MOD = 998244353;

struct mod_int {
    int val;

    mod_int(long long v = 0) {
        if (v < 0) v = v % MOD + MOD;
        if (v >= MOD) v %= MOD;
        val = v;
    }

    static int mod_inv(int a, int m = MOD) {
        // https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Example
        int g = m, r = a, x = 0, y = 1;

        while (r != 0) {
            int q = g / r;
            g %= r; swap(g, r);
            x -= q * y; swap(x, y);
        }

        return x < 0 ? x + m : x;
    }

    explicit operator int() const {
        return val;
    }

    mod_int& operator+=(const mod_int &other) {
        val += other.val;
        if (val >= MOD) val -= MOD;
        return *this;
    }

    mod_int& operator-=(const mod_int &other) {
        val -= other.val;
        if (val < 0) val += MOD;
        return *this;
    }

    static unsigned fast_mod(uint64_t x, unsigned m = MOD) {
#if !defined(_WIN32) || defined(_WIN64)
        return x % m;
#endif
        // Optimized mod for Codeforces 32-bit machines.
        // x must be less than 2^32 * m for this to work, so that x / m fits in a 32-bit integer.
        unsigned x_high = x >> 32, x_low = (unsigned) x;
        unsigned quot, rem;
        asm("divl %4\n"
            : "=a" (quot), "=d" (rem)
            : "d" (x_high), "a" (x_low), "r" (m));
        return rem;
    }

    mod_int& operator*=(const mod_int &other) {
        val = fast_mod((uint64_t) val * other.val);
        return *this;
    }

    mod_int& operator/=(const mod_int &other) {
        return *this *= other.inv();
    }

    friend mod_int operator+(const mod_int &a, const mod_int &b) { return mod_int(a) += b; }
    friend mod_int operator-(const mod_int &a, const mod_int &b) { return mod_int(a) -= b; }
    friend mod_int operator*(const mod_int &a, const mod_int &b) { return mod_int(a) *= b; }
    friend mod_int operator/(const mod_int &a, const mod_int &b) { return mod_int(a) /= b; }

    mod_int& operator++() {
        val = val == MOD - 1 ? 0 : val + 1;
        return *this;
    }

    mod_int& operator--() {
        val = val == 0 ? MOD - 1 : val - 1;
        return *this;
    }

    mod_int operator++(int) { mod_int before = *this; ++*this; return before; }
    mod_int operator--(int) { mod_int before = *this; --*this; return before; }

    mod_int operator-() const {
        return val == 0 ? 0 : MOD - val;
    }

    bool operator==(const mod_int &other) const { return val == other.val; }
    bool operator!=(const mod_int &other) const { return val != other.val; }

    mod_int inv() const {
        return mod_inv(val);
    }

    mod_int pow(long long p) const {
        assert(p >= 0);
        mod_int a = *this, result = 1;

        while (p > 0) {
            if (p & 1)
                result *= a;

            a *= a;
            p >>= 1;
        }

        return result;
    }

    friend ostream& operator<<(ostream &stream, const mod_int &m) {
        return stream << m.val;
    }
};

struct mod_matrix_fixed_size {
    static const int SIZE = 2;

    mod_int values[SIZE][SIZE];

    mod_matrix_fixed_size() {
        for (int i = 0; i < SIZE; i++)
            for (int j = 0; j < SIZE; j++)
                values[i][j] = 0;
    }

    mod_matrix_fixed_size(const vector<vector<mod_int>> &v) {
        for (int i = 0; i < SIZE; i++)
            for (int j = 0; j < SIZE; j++)
                values[i][j] = v[i][j];
    }

    mod_int *operator[](int index) { return values[index]; }
    const mod_int *operator[](int index) const { return values[index]; }

    void make_identity() {
        for (int i = 0; i < SIZE; i++)
            for (int j = 0; j < SIZE; j++)
                values[i][j] = i == j ? 1 : 0;
    }

    mod_matrix_fixed_size operator*(const mod_matrix_fixed_size &other) const {
        mod_matrix_fixed_size product;

        for (int i = 0; i < SIZE; i++)
            for (int j = 0; j < SIZE; j++)
                if (values[i][j] != 0)
                    for (int k = 0; k < SIZE; k++)
                        product[i][k] += values[i][j] * other[j][k];

        return product;
    }

    mod_matrix_fixed_size& operator*=(const mod_matrix_fixed_size &other) {
        return *this = *this * other;
    }

    mod_matrix_fixed_size power(long long p) const {
        assert(p >= 0);

        mod_matrix_fixed_size m = *this;
        mod_matrix_fixed_size result;
        result.make_identity();

        while (p > 0) {
            if (p & 1)
                result *= m;

            p >>= 1;

            if (p > 0)
                m *= m;
        }

        return result;
    }

    void print() const {
        for (int i = 0; i < SIZE; i++)
            for (int j = 0; j < SIZE; j++)
                cout << values[i][j] << (j < SIZE - 1 ? ' ' : '\n');
    }
};

struct segment {
    mod_matrix_fixed_size m;

    segment(mod_int m00 = 1, mod_int m01 = 0, mod_int m10 = 0, mod_int m11 = 1) {
        m = mod_matrix_fixed_size({{m00, m01}, {m10, m11}});
    }

    void join(const segment &other) {
        m *= other.m;
    }

    void join(const segment &a, const segment &b) {
        m = a.m * b.m;
    }
};

int right_half[32];

struct basic_seg_tree {
    static const bool POWER_OF_TWO_MODE = true;

    int tree_n = 0;
    vector<segment> tree;

    basic_seg_tree(int n = -1) {
        if (n >= 0)
            init(n);
    }

    void init(int n) {
        if (POWER_OF_TWO_MODE) {
            tree_n = 1;

            while (tree_n < n)
                tree_n *= 2;
        } else {
            tree_n = n;
        }

        tree.assign(2 * tree_n, segment());
    }

    // Builds our tree from an array in O(n).
    void build(const vector<segment> &initial) {
        int n = initial.size();
        init(n);
        assert(n <= tree_n);

        for (int i = 0; i < n; i++)
            tree[tree_n + i] = initial[i];

        for (int position = tree_n - 1; position > 0; position--)
            tree[position].join(tree[2 * position], tree[2 * position + 1]);
    }

    segment query(int a, int b) {
        assert(0 <= a && a <= b && b <= tree_n);
        segment answer;
        int r_size = 0;

        for (a += tree_n, b += tree_n; a < b; a /= 2, b /= 2) {
            if (a & 1)
                answer.join(tree[a++]);

            if (b & 1)
                right_half[r_size++] = --b;
        }

        for (int i = r_size - 1; i >= 0; i--)
            answer.join(tree[right_half[i]]);

        return answer;
    }

    segment query_single(int index) {
        assert(0 <= index && index < tree_n);
        return tree[tree_n + index];
    }

    void join_up(int position) {
        while (position > 1) {
            position /= 2;
            tree[position].join(tree[2 * position], tree[2 * position + 1]);
        }
    }

    void update(int index, const segment &seg) {
        assert(0 <= index && index < tree_n);
        int position = tree_n + index;
        tree[position] = seg;
        join_up(position);
    }
};


struct event {
    long long distance = 0, velocity = 1;
    int index, row, col;

    event() {}

    event(long long _distance, long long _velocity, int _index, int _row, int _col)
        : distance(_distance), velocity(_velocity), index(_index), row(_row), col(_col) {
        assert(distance >= 0 && velocity > 0);
    }

    mod_int get_time() const {
        return mod_int(distance) / velocity;
    }

    bool operator<(const event &other) const {
        return distance * other.velocity < other.distance * velocity;
    }
};

int main() {
    int N;
    IO::read_int(N);
    vector<int> X(N), V(N);
    vector<mod_int> L(N), R(N);
    const mod_int INV100 = mod_int(100).inv();

    for (int i = 0; i < N; i++) {
        int P;
        IO::read_int(X[i], V[i], P);
        R[i] = P * INV100;
        L[i] = 1 - R[i];
    }

    basic_seg_tree tree(N);
    vector<segment> transitions(N);

    for (int i = 0; i < N; i++)
        transitions[i].m = mod_matrix_fixed_size({{L[i], R[i]}, {L[i], R[i]}});

    tree.build(transitions);

    auto &&get_probability = [&]() {
        return tree.tree[1].m[0][0] + tree.tree[1].m[0][1];
    };

    vector<event> events;

    for (int i = 1; i < N; i++) {
        long long distance = X[i] - X[i - 1];
        events.emplace_back(distance, V[i] + V[i - 1], i, 1, 0);

        if (V[i] > V[i - 1])
            events.emplace_back(distance, V[i] - V[i - 1], i, 0, 0);
        else if (V[i - 1] > V[i])
            events.emplace_back(distance, V[i - 1] - V[i], i, 1, 1);
    }

    sort(events.begin(), events.end());
    mod_int total = 0, previous_probability = 1;

    for (event &ev : events) {
        transitions[ev.index].m[ev.row][ev.col] = 0;
        tree.update(ev.index, transitions[ev.index]);

        mod_int time = ev.get_time();
        mod_int current_probability = get_probability();
        total += (previous_probability - current_probability) * time;
        previous_probability = current_probability;
    }

    cout << total << '\n';
}


Comments

Submit
0 Comments
More Questions

630D - Hexagons
1690D - Black and White Stripe
1688D - The Enchanted Forest
1674C - Infinite Replacement
712A - Memory and Crow
1676C - Most Similar Words
1681A - Game with Cards
151C - Win or Freeze
1585A - Life of a Flower
1662A - Organizing SWERC
466C - Number of Ways
1146A - Love "A"
1618D - Array and Operations
1255A - Changing Volume
1710C - XOR Triangle
415C - Mashmokh and Numbers
8A - Train and Peter
591A - Wizards' Duel
1703G - Good Key Bad Key
1705A - Mark the Photographer
1707A - Doremy's IQ
1706B - Making Towers
1325B - CopyCopyCopyCopyCopy
1649C - Weird Sum
1324B - Yet Another Palindrome Problem
525A - Vitaliy and Pie
879A - Borya's Diagnosis
1672B - I love AAAB
1673A - Subtle Substring Subtraction
1345A - Puzzle Pieces