LED (DHBB CT)

Xem PDF

Điểm: 400 (p) Thời gian: 1.0s Bộ nhớ: 1023M Input: bàn phím Output: màn hình

Minh nhận được một chiếc máy tính bấm tay màn hình LCD. Màn hình được chia thành các ô biểu diễn chữ số, mỗi ô gồm \(7\) vạch LED và mỗi chữ số sẽ tương ứng với một số vạch LED được kích hoạt nổi màu đen trên ô đó. Cách hiển thị các số như sau:

Minh bấm số nguyên dương \(N\) hiển thị trên màn hình và thắc mắc 2 câu hỏi:

  1. Có bao nhiêu vạch LED được kích hoạt để hiển thị số \(N\).
  2. Tính số lượng các số lớn hơn \(N\), có thể được hiển thị bởi kích hoạt thêm ít nhất một vạch LED ngoài các vạch đang được kích hoạt để hiển thị số \(N\) (không tắt bất kỳ vạch LED nào đang hiển thị và không kích hoạt vạch LED trên ô chưa có vạch kích hoạt).

Yêu cầu: Hãy lập trình giúp Minh trả lời \(2\) câu hỏi trên.

Input

  • Dòng đầu tiên ghi mã câu hỏi \(V\)\(1\) hoặc \(2\).
  • Dòng thứ 2 ghi số nguyên dương \(N\) (không bắt đầu bởi chữ số \(0\)).

Output

  • Nếu \(V=1\) thì in ra số vạch LED được kích hoạt để hiển thị số \(N\).
  • Nếu \(V=2\) thì in ra số lượng số lớn hơn \(N\), có thể được hình thành bằng cách kích hoạt thêm ít nhất một vạch LED, bên cạnh các vạch đã kích hoạt được sử dụng để hiển thị số \(N\).

Constraints

  • \(N \leq 10 ^ {18}\)

Scoring

  • Subtask \(1\) (\(45\%\) số điểm): \(V = 1, N \leq 10 ^ {18}\).
  • Subtask \(2\) (\(20\%\) số điểm): \(V = 2, N < 20\)
  • Subtask \(3\) (\(35\%\) số điểm): \(V = 2, 20 \leq N \leq 10 ^ {18}\)

Example

Test 1

Input
1 
823 
Output
17

Test 2

Input
2 
823 
Output
5
Note
  • Ví dụ \(1\): số 8 dùng 7 vạch, số 2 dùng 5 vạch, số 3 dùng 5 vạch, do đó cần 17 vạch.
  • Ví dụ \(2\): có 5 số lớn hơn 823 là 828, 829, 883, 888, 889.

Bình luận


  • 0
    IGCONITO    9:48 p.m. 14 Tháng 5, 2021

    em thấy cái solution nó khủng quá, ko phù hợp với học sinh lớp 10 thi duyên hải bình thường đâu a @SPyofgame


    • 0
      cuom1999    11:23 p.m. 12 Tháng 6, 2020 đã chỉnh sửa

      @SPyofgame, em đăng 2 bình luận khá tương tự nhau. Em muốn giữ cái nào để anh ẩn bớt 1 cái.

      1 phản hồi

      • 0
        SPyofgame    11:04 p.m. 12 Tháng 6, 2020 chỉnh sửa 4

        Spoiler Alert


        Hint 1

        • Query 1: Tính tổng vạch led bật mỗi chữ số từ số n

        • Query 2: Với mỗi số x > n có cùng độ dài với n. Tăng biến đếm nếu x có chứa các vạch led n

        Hint 2

        • Query 1: Ta có thể tiền xử lí 10 chữ số 0..9 xem nó có bao nhiêu vạch led bật để tiện

        • Query 2: Ta có thể thử xây từng chữ số cho x, từ đó đưa ta đến thuật quy hoạch động chữ số

        Hint 3

        • Query 1: vector<int> csl = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6}; /// Count set-led

        • Query 2:

        Duyệt i từ trái sang phải

        Gọi ctw = count_total_ways là số cách chọn chữ số tại vị trí i

        Gọi clw = count_less_ways là số cách chọn chữ số bé hơn tại vị trí i

        Gọi res là tổng số cách chọn trước đó

        Dựa vào đó ta tính tổng số cách chọn bây giờ

        Hint 4

        • Query 2:

        Ta có thể tiền xử lí xem với mỗi chữ số d = 0..9 thì số cách chọn ctw[d]clw[d] là gì

        ctw[d] là số lượng số x thỏa x chứa các vạch led d bật

        clw[d] là số lượng số x < d thỏa x chứa các vạch led d bật

        Từ đó suy ra công thức toán học

        Hint 5

        • Query 2: Multiplicative Formula: res = res * ctw[d] - clw[d]

        Reference AC code | \(O(log_{10} n)\) + \(O(log_{10} n)\) time | \(O(1)\) auxiliary space | Brute-forces + DP_digit | Online Solving Implementation

        C++
                     ///   0  1  2  3  4  5  6  7  8  9
        vector<int> csl = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6}; /// Đếm số vạch led bật
        vector<int> ctw = {2, 7, 2, 3, 3, 4, 2, 5, 1, 2}; /// Số cách chọn chữ số tại vị trí i
        vector<int> clw = {0, 1, 0, 0, 0, 0, 0, 2, 0, 1}; /// Số cách chọn chữ số bé hơn tại vị trí i
        inline bool isDig(char c) { return '0' <= c && c <= '9'; } /// isDigit(char) ?
        void solve1() /// O(log10 n)
        {
            int res = 0;
            char c;
            while (c = getchar(), !isDig(c));
            do res += csl[c - '0']; while (isDig(c = getchar()));
            cout << res;
        }
        
        void solve2() /// O(log10 n)
        {
            ll res = 1;
            char c;
            while (c = getchar(), !isDig(c));
            do res = res * ctw[c - '0'] - clw[c - '0']; while (isDig(c = getchar()));
            cout << res - 1; /// Bỏ qua trường hợp bằng nhau
        }
        

        • 0
          SPyofgame    11:04 p.m. 12 Tháng 6, 2020 chỉnh sửa 4

          Spoiler Alert


          Hint 1

          • Query 1: Tính tổng vạch led bật mỗi chữ số từ số n

          • Query 2: Với mỗi số x > n có cùng độ dài với n. Tăng biến đếm nếu x có chứa các vạch led n

          Hint 2

          • Query 1: Ta có thể tiền xử lí 10 chữ số 0..9 xem nó có bao nhiêu vạch led bật để tiện

          • Query 2: Ta có thể thử xây từng chữ số cho x, từ đó đưa ta đến thuật quy hoạch động chữ số

          Hint 3

          • Query 1: vector<int> csl = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6}; /// Count set-led

          • Query 2: Thử xây từng chữ số với hàm đệ quy magic(int index, bool isGreater)

          Với index là vị trí các chữ số của n từ trái sang phải

          Với isGreater là biến kiểm tra xem số hiện tại lớn hơn n chưa

          Ta thử xây chữ số tiếp theo là chữ số có chứa các vạch led bật sẵn

          Hint 4

          • Query 2:

          Ta có thể tiền xử lí xem với mỗi chữ số d = 0..9 thì có những số nextd nào có vạch led d bật, tức những cách thỏa mãn

          Nếu số hiện tại đã lớn hơn n, thì mình có thể chọn mọi số nextd <=> lower_limit = 0

          Nếu số hiện tại chưa lớn hơn n, thì mình chỉ có thể chọn mọi số nextd ≥ d <=> lower_limit = d

          Nếu số hiện tại đã lớn hơn n hoặc nextd > d thì isGreater = true (khởi tạo là False nhé)

          Sau đó ta đệ quy chữ số tiếp theo

          Hint 5

          • Query 2: Recursive Formula: res = res + magic(index + 1, isGreater || (nextd > lower_limit))

          Reference AC code | \(O(log_{10} n)\) + \(O(log_{10} n * 2 * 7)\) time | \(O(1)\) auxiliary space | Brute-forces + DP_digit | Adjacency List Implementation

          C++
          /// Tiền xử lí các vạch led bật
          vector<int> cntled = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
          void solve1()
          {
              /// Biểu diễn số dưới dạng xâu
              string s;
              cin >> s;
          
              /// Kết quả là tổng số lượng vạch led bật
              int res = 0;
              for (char c : s)
                  res += cntled[c - '0'];
          
              cout << res;
          }
          
          /// Tiền xử lí
          /// vector thứ n biểu diễn tất cả các đèn led mà các vạch led có trong n được bật
          vector<vector<int> > G = {
              {0, 8},                 /// [0]
              {0, 1, 3, 4, 7, 8, 9},  /// [1]
              {2, 8},                 /// [2]
              {3, 8, 9},              /// [3]
              {4, 8, 9},              /// [4]
              {5, 6, 8, 9},           /// [5]
              {6, 8},                 /// [6]
              {0, 3, 7, 8, 9},        /// [7]
              {8},                    /// [8]
              {8, 9},                 /// [9]
          };
          
          int n;                  /// Độ dài của số nhận vào
          vector<int> v;          /// vector chứa các chữ số
          vector<vector<ll> > f;  /// vector 2 chiều quy hoạch động
          /// hàm magic(i, ign)
          /// tại vị trí (i) của số biểu diễn bởi vector (v)
          /// đếm số cách mà xây dựng được số có (ign) = true
          ll magic(int i = 0, bool ign = false) /// O(n * 2 * 7)
          {
              /// Nếu đã duyệt hết vector
              if (i >= n) return ign;
          
              /// Dùng con trỏ để tiện tính toán
              ll &res = f[i][ign];
              if (res != -1) return res; /// Nếu đã được tính trước đó
              else res = 0;              /// Ngược lại thì reset giá trị
          
              /// Chúng ta chỉ đếm các số lớn hơn
              int lim = ign ? 0 : v[i];
              for (int d : G[v[i]])
                  if (d >= lim)
                      res += magic(i + 1, ign || (d > lim));
          
              /// Đừng quên trả về kết quả :D
              return res;
          }
          
          void solve2()
          {
              /// Biểu diễn số dưới dạng xâu
              string s;
              cin >> s;
          
              /// Dùng vector (v) độ dài (n) để lưu trữ các chữ số
              n = s.size();
              for (char c : s) v.pb(c - '0');
          
              /// Khởi tạo -1 tức là chưa được tính trước đó
              f.assign(n + 1, vector<ll>(2, -1));
              cout << magic();
          }
          

          Reference AC code | \(O(log_{10} n)\) + \(O(log_{10} n * 2 * 7)\) time | \(O(1)\) auxiliary space | Brute-forces + DP_digit

          C++
          /// Tiền xử lí các vạch led bật
          vector<int> cntled = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
          void solve1()
          {
              ll n = readLong();
              int res = 0;       /// Kết quả là tổng số lượng vạch led bật
              do res += cntled[n % 10]; while (n /= 10);
              cout << res;
          }
          
          
          /// Tiền xử lí
          /// bit thứ (i) của vector thứ (n) biểu diễn có thể chuyển đổi từ (led-i) sang (led-n) hay không
          vector<vector<bool> > G = {
              {1, 0, 0, 0, 0, 0, 0, 0, 1, 0}, /// [0] - 0, 8
              {1, 1, 0, 1, 1, 0, 0, 1, 1, 1}, /// [1] - 0, 1, 3, 4, 7, 8, 9
              {0, 0, 1, 0, 0, 0, 0, 0, 1, 0}, /// [2] - 2, 8
              {0, 0, 0, 1, 0, 0, 0, 0, 1, 1}, /// [3] - 3, 8, 9
              {0, 0, 0, 0, 1, 0, 0, 0, 1, 1}, /// [4] - 4, 8, 9
              {0, 0, 0, 0, 0, 1, 1, 0, 1, 1}, /// [5] - 5, 6, 8, 9
              {0, 0, 0, 0, 0, 0, 1, 0, 1, 0}, /// [6] - 6, 8
              {1, 0, 0, 1, 0, 0, 0, 1, 1, 1}, /// [7] - 0, 3, 7, 8, 9
              {0, 0, 0, 0, 0, 0, 0, 0, 1, 0}, /// [8] - 8
              {0, 0, 0, 0, 0, 0, 0, 0, 1, 1}, /// [9] - 8, 9
          };
          
          int n;                  /// Độ dài của số nhận vào
          vector<int> v;          /// vector chứa các chữ số
          vector<vector<ll> > f;  /// vector 2 chiều quy hoạch động
          /// hàm magic(i, ign)
          /// tại vị trí (i) của số biểu diễn bởi vector (v)
          /// đếm số cách mà xây dựng được số có (ign) = true
          ll magic(int i = 0, int ign = false) /// O(n * 2 * 9)
          {
              /// Nếu đã duyệt hết vector
              if (i >= n) return ign;
          
              /// Dùng con trỏ để tiện tính toán
              ll &res = f[i][ign];
              if (res != -1) return res; /// Nếu đã được tính trước đó
              else res = 0;              /// Ngược lại thì reset giá trị
          
              /// Chúng ta chỉ chọn những chữ số có thể chuyển đổi được
              int lim = ign ? 0 : v[i];
              for (int d = 9; d >= lim; --d)
                  if (G[v[i]][d] == true)
                      res += magic(i + 1, ign || (d > lim));
          
              /// Đừng quên trả về kết quả :D
              return res;
          }
          
          void solve2()
          {
              /// Biểu diễn số dưới dạng xâu
              string s;
              cin >> s;
          
              /// Dùng vector (v) độ dài (n) để lưu trữ các chữ số
              n = s.size();
              for (char c : s) v.pb(c - '0');
          
              /// Khởi tạo -1 tức là chưa được tính trước đó
              f.assign(n + 1, vector<ll>(2, -1));
              cout << magic();
          }
          

          • 0
            tuandq    6:30 p.m. 4 Tháng 6, 2020 chỉnh sửa 2

            ...

            1 phản hồi