Hướng dẫn giải của [VTT Q4 Contest 09] Bài 1: Khóa số [LOCK]


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 dãy ~n~ chữ số và ~m~ lần bấm phím: phím 1 cộng thêm 1 (modulo 10) vào mọi chữ số, phím 2 dịch vòng sang phải một vị trí. Cần in trạng thái cuối cùng. Nhận xét then chốt: phép cộng 1 tác động lên tất cả chữ số như nhau nên nó không phụ thuộc vị trí, do đó giao hoán với phép dịch vòng.

Sub 1: Mô phỏng — ~O(n \cdot m)~, dùng khi ~n, m \le 1000~

Làm đúng theo đề: với mỗi phím, hoặc cộng 1 cho từng chữ số, hoặc dịch vòng cả xâu. Nếu chỉ nộp sub này: đúng 17/20 test (3 test lớn bị quá thời gian).

Sub 2: Đếm số lần bấm — ~O(n + m)~

Vì phép cộng và phép dịch vòng không ảnh hưởng lẫn nhau, kết quả chỉ phụ thuộc vào số phím 1 (gọi là ~c_1~) và số phím 2 (gọi là ~c_2~), không phụ thuộc thứ tự. Mỗi chữ số được cộng ~c_1 \bmod 10~ và bị dịch sang phải ~c_2 \bmod n~ vị trí (vòng tròn). Chữ số ở vị trí ~i~ (đánh số từ 0) chuyển tới vị trí ~(i + c_2) \bmod 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 dữ liệu; khi ~n, m \le 1000~ gọi sub1, ngược 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. Chương trình đạt 20/20 test.

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

int n, m;
string s, k;

// Sub 1: mô phỏng từng lần bấm phím — O(n*m)
void sub1() {
    for (char c : k) {
        if (c == '1') {
            for (int i = 0; i < n; i++) s[i] = (s[i] - '0' + 1) % 10 + '0';
        } else {
            rotate(s.begin(), s.end() - 1, s.end()); // dịch vòng sang phải 1 vị trí
        }
    }
    cout << s << "\n";
}

// Sub 2: phím 1 cộng cho mọi chữ số như nhau, phím 2 chỉ dịch vòng
// => chỉ cần đếm số phím 1 (cộng) và số phím 2 (dịch) — O(n+m)
void sub2() {
    int add = 0;
    long long rot = 0;
    for (char c : k) {
        if (c == '1') add++; else rot++;
    }
    add %= 10;
    rot %= n;
    string r(n, '0');
    for (int i = 0; i < n; i++)
        r[(i + rot) % n] = (s[i] - '0' + add) % 10 + '0';
    cout << r << "\n";
}

int main() {
    freopen("LOCK.INP", "r", stdin);
    freopen("LOCK.OUT", "w", stdout);
    ios::sync_with_stdio(false); cin.tie(nullptr);
    cin >> n >> s >> m >> k;
    if (n <= 1000 && m <= 1000) 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.