Trực nhật

Xem PDF




Thời gian:
Pypy 3 5.0s
Python 3 15.0s
Bộ nhớ:
Pypy 3 512M
Python 3 512M

Tác giả:
Dạng bài
Điểm: 300 (p) Thời gian: 1.1s Bộ nhớ: 256M Input: bàn phím Output: màn hình

Lớp \(11\) chuyên Tin có \(n\) học sinh, thầy chủ nhiệm Linh Phan muốn chọn ra một số bạn ở lại trực nhật lớp. Để thêm tính hấp dẫn và công bằng, thầy viết một đoạn code cấp cho mỗi bạn một số tự nhiên ngẫu nhiên và quy định rằng, nếu bạn nào nhận được số có tổng các ước dương của nó nhỏ hơn hai lần số đó thì phải đi trực nhật.

Một lần không may mắn, máy tính của thầy Linh Phan đã sinh ra các số mà sau khi cấp phát cho học sinh thì không có học sinh nào phải ở lại trực nhật. Rút kinh nghiệm từ lần đó, thầy đã chuẩn bị sẵn một dãy số, rồi nhờ các em đội tuyển Tin tính xem có bao nhiêu số có tổng các ước dương nhỏ hơn hai lần số đó, nếu số lượng số này đủ nhiều thì thầy sẽ lấy dãy số đó để cấp cho các bạn trong lớp.

Yêu cầu: Cho số nguyên dương \(n\) và dãy số \(a_1\), \(a_2\),..., \(a_{n – 1}\), \(a_n\). Hãy giúp thầy Linh Phan xác định xem với dãy số này thì có bao nhiêu em học sinh phải làm nhiệm vụ trực nhật.

Input

  • Dòng đầu ghi số nguyên dương \(n\), số học sinh trong lớp.
  • Dòng thứ hai gồm \(n\) số nguyên dương \(a_1\), \(a_2\),..., \(a_{n–1}\), \(a_n\).

Output

  • Gồm một số duy nhất là số học sinh phải ở lại trực nhật tương ứng với dãy số input.

Constraints

  • \(N\leq 10^6\)
  • \(a_i\leq 5.10^6\)

Scoring

  • Subtask \(1\) (\(70\%\) số điểm): \(N\leq 10^3, a_i\leq 10^4\)
  • Subtask \(2\) (\(15\%\) số điểm): \(N\leq 10^4, a_i\leq 5.10^6\)
  • Subtask \(3\) (\(15\%\) số điểm): Không có ràng buộc gì thêm

Example

Test 1

Input
5
3 6 9 12 9 
Output
3
Note
  • Tổng ước dương của các số là:
  • Số \(3\): \(1+3=4<2.3=6\);
  • Số \(6\): \(1+2+3+6=2.6=12\)
  • Số \(9\): \(1+3+9=13<2.9=18\)
  • Số \(12\): \(1+2+3+4+6+12=28>2.12=24\)
  • Số \(9\): \(1+3+9=13<2 * 9=18\)

  • Vậy có \(3\) số có tổng ước nhỏ hơn hai lần nó là: \(3, 9 ,9\).


Bình luận


  • 1
    SPyofgame    5:12 p.m. 14 Tháng 6, 2020 chỉnh sửa 13

    Spoiler Alert


    Hint 1

    • Gọi \(check(x)\) là hàm kiểm tra xem \(x\) có thỏa mãn hay không

    Duyệt qua từng số, tăng biến đếm nếu \(check(x) = true\)

    \(Result\) = số lượng \(x \in A\) thỏa \(check(x) = true\)

    Hint 2

    • \(check(x) = true\) <=> \(divisors\_sum(x) < 2 * x\)

    Ta cần tính \(divisor\_sum(x)\) thì việc còn lại là kiểm tra \(O(1)\) khi duyệt \(O(n)\)

    Hint 3

    • Mathematics Approach:

    \(x = p_1 ^ {f_1} * p_2 ^ {f_2} * ... * p_k ^ {f_k}\) với \(p_i\) là thừa số nguyên tố và \(f_i\) là số mũ nguyên dương

    \(divisors\_sum(x) = \Sigma(unique\) \(t = p_1 ^ {f_1^{''} \leq f_1} * p_2 ^ {f_2^{''} \leq f_2} * ... * p_k ^ {f_k^{''} \leq f_k})\)

    <=> \(divisors\_sum(x) = \frac{p_1 ^ {f_1 + 1} - 1}{p_1 - 1} * \frac{p_2 ^ {f_2 + 1} - 1}{p_2 - 1} * ... * \frac{p_k ^ {f_k + 1} - 1}{p_k - 1}\)

    • Precalculation Approach:

    Gọi \(1 \leq d \leq x \leq max\)

    Để tiền xử lí thì \(\forall x\) ta tìm các ước \(d\) và tính tổng

    <=> Lần lượt tăng giá trị các bội \(x\) lên \(d\) đơn vị

    Hint 4

    • Mathematics Approach:

    Sàng nguyên tố để lấy tất cả các số nguyên tố \(p \leq max\)

    Khởi tạo $sum = $ rồi liên tục phân tích nhân tử để tách ra từng phần \(p_i ^ {f_i}\) để thực hiện tính toán

    • Precalculation Approach:

    Khởi tạo \(divisors\_sum(x) = 0\) \(\forall x \in [1..max]\)

    \(\forall x \in [1..max]\) tăng giá trị \(divisors\_sum[k * x]\) lên thêm \(x\) đơn vị (\(k \in ℕ^*\) and \(k * x \leq max\))


    Reference AC code |\(O(n)\) time + \(O(n)\) * \(O(log_2 n)\) query | \(O(n)\) auxiliary space | Online Solving, Sieve, Math

    C++
    vector<int> prime; /// mang cac so nguyen to
    vector<int> lpf;   /// lowest prime factor | lpf[x] la uoc nguyen to nho nhat cua x
    
    /// Sang nguyen to trong O(n)
    void sieve(int lim = LIM) {
        prime.assign(1, 2);
        lpf.assign(lim + 1, 2);
    
        lpf[1] = 1; /// can than lap vo han
        for (int i = 3; i <= lim; i += 2) {
            if (lpf[i] == 2) prime.pb(lpf[i] = i);
            for (int j = 0; j < sz(prime) && prime[j] <= lpf[i] && prime[j] * i <= lim; ++j)
                lpf[prime[j] * i] = prime[j];
        }
    }
    
    /// Tinh (x ^ n) trong O(log n)
    inline ll pw(ll x, ll n) {
        ll res = 1;
        while (n > 0) {
            if (n & 1) res = res * x;
            n >>= 1;
            x = x * x;
        }
        return res;
    }
    
    /// Kiem tra xem (x) co thoa man khong
    bool check(int x) {
        int t = x;
    
        ll sum = 1;
        while (x > 1) {
            /// p la so nguyen to, f la so mu
            int p = lpf[x], f = 0;
    
            /// chia x cho uoc nguyen to nho nhat cua x toi khi nao khong con uoc do nua
            /// <=> tach nhan tu (p ^ f) ra khoi x
            do x /= p, f++; while (p == lpf[x]);
    
            /// dung cong thuc toan hoc
            sum *= (pw(p, f + 1) - 1) / (p - 1); 
        }
    
        return sum < 2 * t;
    }
    
    /// Ham chinh
    int main()
    {
        /// Tien xu li
        sieve(5e6 + 100);
    
        /// Xu li
        int res = 0;
        for (int n = readInt(); n--; res += check[readInt()]); /// Duyet qua tung phan tu
    
        /// Xuat ket qua
        cout << res;
        return 0;
    }
    

    Reference AC code | \(O(n\) \(log_2 n)\) time + \(O(n)\) * \(O(1)\) query | \(O(n)\) auxiliary space | Online Solving, Precalculation

    C++
    int main()
    {
        /// Tien xu li: div_sum[x] = tong cac uoc duong cua x
        int lim = 5e6;
        vector<int> div_sum(lim + 1, 0);
        for (int i = 1; i <= lim; ++i)
            for (int j = i; j <= lim; j += i) /// Duyet qua cac boi cua (i)
                div_sum[j] += i;              /// Lan luot cong vao boi (i) cac uoc cua no
    
        /// Tien xu li: div_sum[x] < 2 * x <=> check[x] = true
        vector<bool> check(lim + 1);
        for (int i = 0; i <= lim; ++i)
            check[i] = (div_sum[i] < i * 2);
    
        /// Xu li
        int res = 0;
        for (int n = readInt(); n--; res += check[readInt()]); /// Duyet qua tung phan tu
    
        /// Xuat ket qua
        cout << res;
        return 0;
    }
    
    • 8 bình luận nữa