Thi Đấu Mười Môn

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ả: huunguyenhuunguyen

Lời giải: Thi Đấu Mười Môn

Hướng tiếp cận

Bài toán yêu cầu phân N thí sinh vào N môn thi (hoán vị) sao cho tổng điểm + thưởng lớn nhất. Với N20, ta dùng DP bitmask.

Nhận xét quan trọng

  1. Xét phân công từng môn thi theo thứ tự 1,2,,N. Khi phân xong k môn đầu, ta biết tập thí sinh đã được chọn (bitmask) và tổng điểm k môn đầu.
  2. Phần thưởng chỉ phụ thuộc vào tổng điểm Ki môn đầu tiên. Khi ta vừa phân xong môn k, ta kiểm tra các bonus có Ki=k.
  3. Trạng thái DP: dp[mask] = tổng điểm tối đa khi đã phân các thí sinh trong mask vào |mask| môn đầu tiên (|mask| = popcount).

Thuật toán

  1. Khởi tạo dp[0]=0, còn lại =.
  2. Duyệt mọi mask từ 0 đến 2N1:
    • Đặt k=popcount(mask) (số môn đã phân).
    • Với mỗi thí sinh i chưa dùng (imask):
      • Thí sinh i thi môn k+1, được si,k+1 điểm.
      • mask=mask|(1i).
      • score=dp[mask]+si,k+1.
      • Kiểm tra bonus: với mỗi bonus có Kj=k+1, nếu scorePj thì score+=Aj.
      • Cập nhật dp[mask]=max(dp[mask],score).
  3. Đáp án: dp[(1N)1].

Độ phức tạp

  • Thời gian: O(2N·N·B)
  • Bộ nhớ: O(2N)

Với N=20: 220·20·204·108 — vừa đủ trong 2 giây với C++.


Bình luận

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

gnatmake 12.2.0 a68g 3.1.2 nasm 2.16.1 as_x64 2.46 awk 1.3.4 gcc 16.1.0 csc 6.12.0.200 g++ 16.1.0 g++-themis 16.1.0 g++17 16.1.0 g++20 16.1.0 g++23 16.1.0 clang++ 22.1.6 dmd 2.112.0 dart 3.12.1 gforth 0.7.3 gfortran 12.2.0 go 1.26.3 groovyc 5.0.6 javac 25.0.3 node 26.2.0 kotlinc 2.3.21 sbcl 2.2.9 lua 5.4.8 nim 2.2.10 fpc 3.2.2 fpc-themis 3.2.2 perl 5.36.0 php 8.5.6 pike 8.0 pypy3 7.3.23 python3 3.14.5 racket 8.7 ruby 4.0.5 rustc 1.96.0 csc 5.3.0 ctoj-scratch 0.0.1 sed 4.9 tclsh 8.6 bun 1.3.14 deno 2.8.1 v 0.5.1 zig 0.16.0