Giải quyết Bài Toán "Super Telephone" Với Trie Nén và Quy Hoạch Động

Bài toán yêu cầu xử lý giá trị trong phạm vi [0, 2^n) khi thực hiện các thao tác với người giàu. Trước hết xem xét trường hợp B = 20, nơi dữ liệu được xử lý dưới dạng nhị phân.

Cấu trúc 01-trie trong khoảng [0, 2^n) là giải pháp hiệu quả. Khi giá trị dị biến toàn cục là 0, phạm vi [0, y] có thể phân tách thành tối đa n cây nhị phân con đầy đủ. Nếu giá trị dị biến v khác 0, số lượng cây con không thay đổi nhưng thứ tự truy cập nhánh tại mỗi tầng bị ảnh hưởng.

Đối với B = 5/6/7, cần áp dụng trie nén bằng cách phân tách các tầng thành khối. Xác định chuỗi tỉ lệ khối c_1, c_2, ..., c_B (với ∑c_i = 20). Khối đầu tiên chứa 1 nút, mỗi nút ở khối i sẽ có 2^{c_i} nút con ở khối i+1.

Chi phí bộ nhớ được tính bằng công thức:

f(c_i) = 1 + 2∑_{k=0}^{c_i-1}4^k - 2^{c_i}

Tổng chi phí: ∑_{i=1}^B(2^{∑_{j=1}^{i-1}c_j} × f(c_i))

Sử dụng quy hoạch động với dp[i][j] biểu thị chi phí tối thiểu khi chọn i khối đầu với tổng j tầng. Kết quả tối ưu:

  • B=5: [9,5,3,2,1]
  • B=6: [8,5,3,2,1,1]
  • B=7: [8,4,3,2,1,1,1]

Mã khởi tạo trie nén:

#include <bits/stdc++.h>

void khoiTao(int B) {
  std::vector<int> c_khoi;
  switch(B) {
    case 5: c_khoi = {9,5,3,2,1}; break;
    case 6: c_khoi = {8,5,3,2,1,1}; break;
    case 7: c_khoi = {8,4,3,2,1,1,1}; break;
  }

  std::unordered_map<uint64_t, int> bangHash;
  std::vector<std::vector<int>> cayCon(MAX_NUT);

  for(auto s : c_khoi) {
    std::vector<std::pair<uint64_t, int>> mangMoi;
    for(int i=0; i<cayCon.size(); i+=(1<<s)) {
      uint64_t hashCha = 0;
      std::vector<uint64_t> tapHash;
      for(int j=0; j<(1<<s); j++) {
        int nut = cayCon[i][j];
        hashCha ^= hash[nut];
        tapHash.push_back(hash[nut]);
      }
      cayConMoi.push_back({tapHash});
      bangHash[hashCha] = taoNutMoi();
    }
    cayCon = mangMoi;
  }
}

Hàm truy vấn:

std::vector<int> timNut(int y, int dich) {
  std::vector<int> ketQua;
  int phepXor = dich;
  int bitPos = 0;

  for(auto s : c_khoi) {
    int khoaBit = (dich >> bitPos) & ((1<<s)-1);
    int gioiHan = (y >> bitPos) & ((1<<s)-1);
    
    if(gioiHan > 0) {
      uint64_t hashTap = 0;
      for(int i=0; i<gioiHan; i++) {
        int nut = cayCon[phepXor][i ^ khoaBit];
        hashTap ^= hash[nut];
      }
      ketQua.push_back(bangHash[hashTap]);
    }
    bitPos += s;
  }
  return ketQua;
}

Thẻ: trie quy-hoach-dong trie-nen xor Luogu

Đăng vào ngày 29 tháng 9 lúc 08:36