Hướng dẫn giải của [VTT Q4 Contest 12] Bài 1: Điền dấu [EXP]


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.

Hướng dẫn giải

Cho ~n~ số 1 và ~m~ số 2, cần đặt dấu +/- trước mỗi số để tổng bằng 0. Bài chỉ cần một nhận xét về tính chẵn lẻ.

Sub 1: Vét cạn — ~O(n \cdot m)~ mỗi bộ dữ liệu, dùng khi ~(n+1)(m+1) \le 10^6~

Thử mọi cách chọn ~x~ số 1 mang dấu + (còn ~n-x~ số mang dấu -) và ~y~ số 2 mang dấu + (còn ~m-y~ số mang dấu -), kiểm tra tổng ~(2x-n) + 2(2y-m)~ có bằng 0 không. Nếu chỉ nộp sub này: đúng 1/20 test (các test còn lại quá lớn nên bị quá thời gian).

Sub 2: Nhận xét chẵn lẻ — ~O(1)~ mỗi bộ dữ liệu

Các số 2 luôn đóng góp một số chẵn, nên tổng bằng 0 đòi hỏi ~n~ chẵn. Khi ~n~ chẵn và ~n > 0~, ta chia các số 1 thành hai nhóm bằng nhau (dấu + và -), rồi xử lý các số 2: nếu ~m~ chẵn thì chia đôi; nếu ~m~ lẻ thì dùng hai số 1 cùng dấu để bù cho số 2 dư (ví dụ ~+1+1-2~). Khi ~n = 0~ thì cần ~m~ chẵn. Bẫy: ~n = 0~ và ~m~ lẻ thì đáp án là NO dù ~n~ chẵn. Nếu chỉ nộp sub này: đúng 20/20 test.

Chương trình hoàn chỉnh

Hàm main đọc ~t~, với mỗi bộ dữ liệu nhỏ thì gọi sub1, còn lại gọi sub2. Khi đi thi nên viết như vậy: sub sau có sai hoặc chưa kịp làm thì vẫn ăn điểm sub trước.

#include <bits/stdc++.h>
using namespace std;

int t, n, m;

// Sub 1: vét cạn — thử mọi số lượng số 1 mang dấu '+' và số 2 mang dấu '+'
void sub1() {
    for (int x = 0; x <= n; x++)
        for (int y = 0; y <= m; y++) {
            // x số 1 dương, n-x số 1 âm, y số 2 dương, m-y số 2 âm
            if ((x - (n - x)) + 2 * (y - (m - y)) == 0) {
                puts("YES");
                return;
            }
        }
    puts("NO");
}

// Sub 2: nhận xét — n phải chẵn; nếu n = 0 thì m phải chẵn
void sub2() {
    if (n % 2 == 0 && (n > 0 || m % 2 == 0)) puts("YES");
    else puts("NO");
}

int main() {
    freopen("EXP.INP", "r", stdin);
    freopen("EXP.OUT", "w", stdout);
    scanf("%d", &t);
    while (t--) {
        scanf("%d %d", &n, &m);
        if ((long long)(n + 1) * (m + 1) <= 1000000) sub1();
        else sub2();
    }
}

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.