Hướng dẫn giải của Bedao Mini Contest 07 - MARKET


Chỉ dùng lời giải này khi không có ý tưởng, và đừng copy-paste code từ lời giải này. Hãy tôn trọng người ra đề và người viết lời giải.
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.

Tác giả: bedao

Nhận xét #1: Giá sử dãy ~s[1...m]~ có trung bình cộng bằng ~x~ thì: ~s[1]+...+s[m] = x \times m~

~\leftrightarrow~ ~s[1]+...+s[m] - x*m = 0~

~\leftrightarrow~ ~(s[1]-x) + …. + (s[m]-x) = 0~

Vì vậy bài toán quay về đếm số dãy con có tổng bằng ~0~ trong dãy sau: ~a[1]-k, \dots, a[n]-k~

Subtask 1:

Vì ~n~ khá bé, ta có thể quay lui để sinh mọi dãy con rồi kiểm tra xem bao nhiêu dãy con trong đó có tổng bằng ~0~.

Độ phức tạp: ~O(2^n)~

Subtask 2:

Chia dãy làm ~2~ nửa bằng nhau (mỗi nửa có kích thước bé hơn hoặc bằng ~18~), ~\frac{n}{2}~ phần tử đầu làm nửa bên trái, ~\frac{n}{2}~ phần tử cuối làm nửa bên phải.

~\rightarrow~ Vậy ~1~ dãy con bất kỳ sẽ rơi vào 3 trường hợp sau:

  • TH1: Nằm hoàn toàn trong nửa bên trái
  • TH2: Nằm hoàn toàn trong nửa bên phải
  • TH3: Có cả phần tử nằm ở nửa bên trái và bên phải

~\rightarrow~ Trường hợp (1) và (2) ta có thể dễ dàng đếm số dãy con có tổng bằng ~0~ tương tự như subtask 1, trường hợp 3 chúng ta sẽ xử lý như sau:

  • Gọi tổng phần tử của các dãy con nằm nửa bên trái là ~s_1~, và tương tự nửa bên phải là ~s_2~. Dễ thấy nếu các dãy con có tổng bằng ~0~ thì ~s_1+s_2 = 0~ hay ~s2 = -s1~.
  • Tạo ~2~ map ~cnt_1~, ~cnt_2~ tương ứng với mỗi nửa. ~cnt_1(s_1)~ là số dãy con có tổng bằng ~s_1~ trong nửa bên trái, tương tự với ~cnt_2(s_2)~ và nửa bên phải.
  • Đáp án là tổng các ~\sum cnt_1(s_1) \times cnt2(-s_1)~ với mọi giá trị ~s_1~ tồn tại.

Độ phức tạp: ~O(2^{\frac{n}{2}} \times \frac{n}{2})~

Code mẫu

#include <bits/stdc++.h>

using namespace std;

int n;
long long a[50], x;
map<long long, int> mp;
long long res = 0;

void gen(int p, int en, bool type, long long s = 0) {
    if (p == en) {
        if (type) {
            ++ mp[s];
        } else {
            res += mp[-s];
        }
        return;
    }
    gen(p+1, en, type, s);
    gen(p+1, en, type, s+a[p]);
}

int main() {
    cin.tie(0)->sync_with_stdio(0);
    cin >> n >> x;
    for (int i = 1; i <= n; ++ i) {
        cin >> a[i];
        a[i] -= x;
    }
    int mid = (1 + n) >> 1;
    gen(1, mid + 1, 1);
    gen(mid + 1, n + 1, 0);
    cout << res - 1;
    return 0;
}

Bình luận

Hãy đọc nội quy trước khi bình luận.


Không có bình luận tại thời điểm này.