Bài viết

3.7: Đếm nhiều bộ


3.7: Đếm nhiều bộ

Số lượng các tập hợp sao cho mỗi số từ 1 đến $ n $ có thể được biểu diễn duy nhất dưới dạng tổng của một số phần tử của tập hợp nhiều

Thí dụ. Ví dụ: nếu $ n = 5 $ thì $ <1,1,1,1,1 >, <1,2,2 >, <1,1,3 > $ hợp lệ.

Tuy nhiên, $ S = <1,1,1,2 > $ không hợp lệ vì 2 có thể được tạo bởi cả $ <1,1 > $ và $ <2 > $ (tức là, 2 có thể được biểu thị vì cả 2 $ = 1 + 1 $ và $ 2 = 2 $), vì vậy điều kiện thứ hai không giữ. Tương tự 3 có thể được tạo bởi $ <2,1 > $ và $ <1,1,1 > $.

$ S = <1,2,4 $> cũng không hợp lệ vì tất cả các số từ $ 1 $ đến $ 5 $ có thể được tạo duy nhất, nhưng tổng các phần tử của $ S $ không phải là $ 5 $.

Tôi đã cố gắng tìm một thuật toán tốt cho vấn đề này trong một thời gian khá dài nhưng không thể giải được. Nó là từ codechef. Tôi đã xem một số giải pháp được gửi nhưng tôi vẫn không thể hiểu được logic để giải quyết vấn đề. GHI CHÚ: Giới hạn thời gian cho câu hỏi là 10 giây và $ n & lt10 ^ 9 $

Đối với tập hợp nhiều, tôi sẽ sử dụng ký hiệu $ S = <(a_1, c_1), (a_2, c_2). > $ $ a_i & lta_j $ nếu $ i & ltj $, nghĩa là $ a_i $ xảy ra $ c_i $ lần trong nhiều tập S.

Cho đến bây giờ tôi đã rút ra một số kết luận

  • Phần tử đầu tiên của đa tập hợp được sắp xếp bắt buộc phải là $ 1 $
  • Cho $ S = <1, a_2 cdots a_k > | a_1 leq a_2 cdots leq a_k $ là một tập hợp theo sau hai thuộc tính sau đó $ forall r & ltk a_ = a_r text ( sum_^ ra_i) + 1 $
  • Cho $ S = <(1, c_1), (a_2, c_2) cdots (a_k, c_k) > | a_1 leq a_2 cdots leq a_k $, trong đó $ a_i $ đang xảy ra $ c_i $ times, tuân theo các thuộc tính bắt buộc thì từ kết luận trên, chúng ta có thể nói rằng $ forall i a_i | n + 1 $ và $ a_i | a_j $ nếu $ j & gt i $.
    Bằng chứng: $ a_ = (a_ic_i + a_i -1) + 1 Mũi tên phải a_i | a_$
  • Bây giờ hãy xem xét $ S = < underbrace <1,1 cdots 1> _, d, d cdots d, dm_1, dm_1 cdots dm_1, dm_2, dm_2 cdots dm_2, cdots > $ tức là tất cả các số tiếp theo sau 1 sẽ là bội số của $ d $. Vì vậy, hãy đặt $ f (n) $ là tổng số các tập hợp như vậy có thể có thì $ f (n) = sum_ f ( frac) $ trong đó tôi đang tính tổng trên tất cả số $ 1 có thể có của $ ($ = d-1 $). Nói cách khác $ f (n-1) = g (n) = sum_g (d) $

Cuối cùng, vấn đề của tôi được giải quyết - tìm $ g (n) $ một cách hiệu quả để nó không vượt quá giới hạn thời gian.


8.3.1. Các đối tượng ChainMap¶

Một lớp ChainMap được cung cấp để liên kết nhanh chóng một số ánh xạ để chúng có thể được coi là một đơn vị duy nhất. Nó thường nhanh hơn nhiều so với việc tạo một từ điển mới và chạy nhiều lệnh gọi update ().

Lớp có thể được sử dụng để mô phỏng các phạm vi lồng nhau và rất hữu ích trong việc tạo khuôn mẫu.

lớp học các bộ sưu tập. ChainMap ( * bản đồ ) ¶

Bản đồ ChainMap nhóm nhiều vùng hoặc các ánh xạ khác với nhau để tạo ra một chế độ xem duy nhất, có thể cập nhật. Nếu không bản đồ được chỉ định, một từ điển trống duy nhất được cung cấp để một chuỗi mới luôn có ít nhất một ánh xạ.

Các ánh xạ cơ bản được lưu trữ trong một danh sách. Danh sách đó là công khai và có thể được truy cập hoặc cập nhật bằng cách sử dụng bản đồ thuộc tính. Không có trạng thái nào khác.

Tra cứu tìm kiếm các ánh xạ cơ bản liên tiếp cho đến khi tìm thấy khóa. Ngược lại, ghi, cập nhật và xóa chỉ hoạt động trên ánh xạ đầu tiên.

Bản đồ chuỗi kết hợp các ánh xạ cơ bản bằng cách tham chiếu. Vì vậy, nếu một trong các ánh xạ cơ bản được cập nhật, những thay đổi đó sẽ được phản ánh trong ChainMap.

Tất cả các phương pháp từ điển thông thường đều được hỗ trợ. Ngoài ra, có một bản đồ thuộc tính, một phương thức để tạo các điều kiện con mới và một thuộc tính để truy cập tất cả trừ ánh xạ đầu tiên:

Danh sách ánh xạ có thể cập nhật của người dùng. Danh sách được sắp xếp từ tìm kiếm đầu tiên đến tìm kiếm cuối cùng. Đây là trạng thái được lưu trữ duy nhất và có thể được sửa đổi để thay đổi ánh xạ nào được tìm kiếm. Danh sách phải luôn chứa ít nhất một ánh xạ.

Trả về ChainMap mới chứa một bản đồ mới, theo sau là tất cả các bản đồ trong phiên bản hiện tại. Nếu m được chỉ định, nó sẽ trở thành ánh xạ mới ở phía trước danh sách ánh xạ nếu không được chỉ định, một dict trống được sử dụng, do đó lệnh gọi d.new_child () tương đương với: ChainMap (<>, * d. bản đồ). Phương thức này được sử dụng để tạo các điều kiện con có thể được cập nhật mà không làm thay đổi các giá trị trong bất kỳ ánh xạ mẹ nào.

Đã thay đổi trong phiên bản 3.4: Tham số m tùy chọn đã được thêm vào.

Thuộc tính trả về ChainMap mới chứa tất cả các bản đồ trong phiên bản hiện tại ngoại trừ phiên bản đầu tiên. Điều này rất hữu ích cho việc bỏ qua bản đồ đầu tiên trong tìm kiếm. Các trường hợp sử dụng tương tự như các trường hợp sử dụng cho từ khóa phi địa phương được sử dụng trong các phạm vi lồng nhau. Các trường hợp sử dụng cũng song song với các trường hợp sử dụng cho hàm super () được tích hợp sẵn. Một tham chiếu đến d.arent tương đương với: ChainMap (* d.maps [1:]).

  • Lớp MultiContext trong gói Enthought CodeTools có các tùy chọn để hỗ trợ ghi vào bất kỳ ánh xạ nào trong chuỗi.
  • Django & # 8217s Lớp ngữ cảnh để tạo mẫu là một chuỗi ánh xạ chỉ đọc. Nó cũng có tính năng đẩy và bật các ngữ cảnh tương tự như phương thức new_child () và thuộc tính cha mẹ ().
  • Công thức Biểu đồ lồng nhau có các tùy chọn để kiểm soát việc ghi và các đột biến khác chỉ áp dụng cho ánh xạ đầu tiên hoặc cho bất kỳ ánh xạ nào trong chuỗi.
  • Một phiên bản Chainmap chỉ đọc được đơn giản hóa rất nhiều.

8.3.1.1. Các ví dụ và công thức về ChainMap

Phần này trình bày các cách tiếp cận khác nhau để làm việc với bản đồ chuỗi.

Ví dụ về mô phỏng chuỗi tra cứu nội bộ Python & # 8217s:

Ví dụ về việc cho phép các đối số dòng lệnh do người dùng chỉ định được ưu tiên hơn các biến môi trường mà lần lượt các biến này được ưu tiên hơn các giá trị mặc định:

Các mẫu ví dụ để sử dụng lớp ChainMap để mô phỏng các ngữ cảnh lồng nhau:

Lớp ChainMap chỉ thực hiện cập nhật (ghi và xóa) cho ánh xạ đầu tiên trong chuỗi trong khi các tra cứu sẽ tìm kiếm toàn chuỗi. Tuy nhiên, nếu bạn muốn ghi và xóa sâu, có thể dễ dàng tạo một lớp con cập nhật các khóa được tìm thấy sâu hơn trong chuỗi:


Các lớp học

Có bảy lớp mới được cung cấp:

Danh sách giải quyết

Ánh xạ

bijection Một ánh xạ một-một. RangeMap Một ánh xạ từ các phạm vi (số / ngày / v.v.) IndexedDict Một ánh xạ giữ thứ tự chèn và cho phép truy cập theo chỉ mục.
Tác giả:Michael Lenzen
Bản quyền:2019 Michael Lenzen
Giấy phép:Giấy phép Apache, Phiên bản 2.0
Trang chủ dự án:
https://github.com/mlenzen/collections-extended

Đây là câu hỏi tổ hợp sao và thanh cổ điển.

Chúng ta cần tìm 4 số, tức là 4 bộ số nguyên dương sao cho tổng của chúng là 7. Vậy số nghiệm là:

Trong đó $ k $ là tổng của chúng và $ n $ là số hạng trong tổng. Vì vậy, đối với trường hợp của chúng tôi, chúng tôi có:

Lưu ý rằng một số giải pháp này là hoán vị vì $ (x, y, z, y) = (1,2,2,2) $ và $ (x, y, z, y) = (2,1,2,2 ) $ được tính hai lần. Nếu bạn muốn các giải pháp như thế này được đưa vào chỉ một lần, tôi không thể nghĩ ra cách nào tốt hơn là đếm.

Đây chỉ là một gợi ý để giúp bạn bắt đầu suy nghĩ về vấn đề. Có thể có một cách khác để xem xét vấn đề này, nhưng bạn cũng có thể chỉ cần đếm số lượng giải pháp. Vì vậy, bạn bắt đầu $ 1 + 1 + 1 + 4 = 7 1 + 1 + 2 + 3 = 7 1 + 1 + 3 + 2 = 7 1 + 1 + 4 + 1 = 7 1 + 2 + 1 + 3 = 7 1 + 2 + 2 + 2 = 7 vdots $

Có thể một cách thông minh hơn một chút để làm điều đó, trước tiên bạn cần lưu ý rằng $ x, y, z, t $ cần phải từ $ <1,2,3,4 > $. Sau đó, tìm xem bạn có thể cộng bao nhiêu cách để nhận được $ 7 $. Bạn nhận được (Lưu ý rằng nếu một số là $ 3 $, thì các số khác phải là $ 1 $ hoặc $ 2 $): $ 1, 1, 1, 4 1, 1, 2, 3 1, 2 , 2, 2. $ Nếu bạn chọn $ 1,1,1,4 $ thì bạn có thể cộng bao nhiêu cách?

$ x + y + z + t = 7 $, nhưng vì chúng đều là số nguyên nên chúng ta viết $ x = m + 1 $, $ y = n + 1 $, $ z = o + 1 $ và $ t = p + 1 $ (trong đó $ m, n, o, p $ là các số nguyên không âm). Khi đó $ m + n + o + p = 3 $. Có ba lựa chọn. Một trong số đó là $ 3 $ và những người khác là $. Một là $ 2 $ và một là $ 1 $ hoặc ba là $ 1 $.

Trường hợp đầu tiên cho các giải pháp $ 4 $, trường hợp thứ hai là $ 12 $ (số cặp có thứ tự của tập con $ $) và $ 4 $ thứ ba. Do đó, có tất cả các giải pháp $ 20 $.


Một thuật toán làm việc

Các mục nhập trong Tam giác Pascal truyền thống (PT từ đây trở đi) đại diện cho hệ số nhị thức trong đó hàng của tam giác là số phần tử trong tập hợp của bạn và cột là độ dài của các tổ hợp bạn muốn tạo. Việc xây dựng tam giác là chìa khóa cho cách chúng ta sẽ tấn công vấn đề trong tầm tay.

Nếu bạn lưu ý rằng đối với PT truyền thống, để có được một mục cụ thể, hãy nói (i, j) Ở đâu Tôi là hàng và j là cột, bạn phải thêm các mục nhập (i - 1, j - 1)(i - 1, j). Đây là một hình ảnh minh họa.

Chúng ta có thể mở rộng điều này thành một tập đa tổng quát trong đó mỗi phần tử được lặp lại một số lần cụ thể. Chúng ta hãy xem xét một vài ví dụ.

Ví dụ 1: v1 = <1, 2, 2>, v2 = <1, 2, 2, 3, 3, 3> và v3 =

Dưới đây chúng tôi có tất cả các kết hợp có thể có của v1 chọn 1 - 3 cũng như v2 chọn 1 - 6.

Hãy để chúng tôi viết ra số lượng kết hợp cho tất cả k cho cả v1 và v2.

Tôi sẽ cung cấp cho bạn số lượng kết hợp cho tất cả k của v3 (Tôi sẽ để người đọc liệt kê chúng).

Chúng tôi kết hợp các kết quả ở trên theo một cách đặc biệt và lưu ý rằng mọi thứ đang bắt đầu trông rất quen thuộc.

Chúng tôi thêm một vài cái làm người giữ chỗ để hoàn thành PT sửa đổi này

Điều đó có nghĩa là gì? Rõ ràng là các số trong mỗi hàng kế tiếp là sự kết hợp của các số trong hàng trước đó. Nhưng bằng cách nào.

Chúng tôi để tần suất của mỗi yếu tố hướng dẫn chúng tôi.

Ví dụ, để có được hàng thứ ba đại diện cho số lượng kết hợp của v2 chọn 1 - 6 (bỏ qua 1 đầu tiên), chúng tôi tìm đến hàng 2. Vì tần số của phần tử thứ 3 là 3, chúng tôi thêm 4 phần tử (3 + 1 .. cũng giống như với hệ số nhị thức để tìm số tổ hợp của các tập hợp có phần tử phân biệt, ta thêm 2 mục vào với nhau hoặc 1 + 1) ở hàng trên với cột nhỏ hơn hoặc bằng cột ta đang tìm. Vì vậy chúng tôi có:

Tiếp tục với logic này, hãy xem liệu chúng ta có thể có được số lượng k-kết hợp cho v3. Vì tần số của phần tử thứ 4 là 4, chúng ta sẽ cần thêm 5 mục nhập với nhau.

Và thực sự, chúng tôi nhận được số lượng chính xác k-kết hợp của v3.

Bạn sẽ nhận thấy rằng chúng tôi đang xây dựng các vectơ này sao cho mỗi vectơ kế tiếp chứa các vectơ trước đó. Chúng tôi làm điều này để có thể xây dựng đúng PT đã sửa đổi của chúng tôi. Điều này tương tự như PT truyền thống trong đó với mỗi hàng kế tiếp, chúng ta chỉ cần thêm một số vào hàng trước đó. PT đã sửa đổi cho các vectơ này là:

Hãy dựng z2 chọn 6 và z3 chọn 9 để xem chúng ta có đúng không:

Cũng giống như một lưu ý nhanh, hàng giữ vị trí đầu tiên tương tự như hàng thứ hai của PT truyền thống (tức là 1 1). Nói một cách lỏng lẻo (xem mã cho các trường hợp cạnh), nếu phần tử đầu tiên có tần số m, hàng đầu tiên của PT đã sửa đổi sẽ chứa m + 1 những cái.


Người giới thiệu

Andrews, G.E: Lý thuyết về các phân vùng. Nhà xuất bản Đại học Cambridge, Cambridge (1998)

Andrews, G.E., Eriksson, K.: Phân vùng số nguyên, ấn bản thứ hai. Nhà xuất bản Đại học Cambridge, Cambridge (2010)

Andrica, D.: Một kết quả tổ hợp liên quan đến sản phẩm của hai hoặc nhiều dẫn xuất. Bò đực. Toán Calcutta. Soc. 92(4), 299–304 (2000)

Andrica, D., Ionaşcu, E.J: Một số mối liên hệ bất ngờ giữa Phân tích và Tổ hợp. Trong: Rassias, T.M., Pardalos, P. (eds.) Toán học Không ranh giới. Các chuyên đề Toán học thuần túy, trang 1–20. Springer, New York (2014)

Andrica, D., Ionaşcu, E.J: Phương trình dấu hiệu cho chuỗi Erdös – Surányi. Số nguyên 15A, 1–9 (2015)

Andrica, D., Tomescu, I.: Trên một dãy số nguyên liên quan đến tích các hàm lượng giác và mức độ liên quan tổ hợp của nó. J. Số nguyên Seq. 5, Điều 02.2.4 (2002)

Andrica, D., Bagdasar O.: Một số nhận xét về 3 phân vùng của multisets. Kỷ yếu IMA TCDM’18 lần thứ 2. Êlectron. Ghi chú Toán rời rạc. 70, 1–8 (2018)

Andrica, D., Bagdasar, O.: Trình tự lặp lại: Kết quả chính. Ứng dụng và Vấn đề. Springer, Berlin (2020)

Andrica, D., Bagdasar, O., Ţurcaş, G.: Số phân hoạch của một tập hợp và các phương trình Diophantine siêu hình. Trong: Raigorodskii, A.M., Rassias, M.T. (eds.) Toán học và Ứng dụng rời rạc. Tối ưu hóa và Ứng dụng của nó, vol. 165, trang 35–55. Springer, Cham (2020)

Andrica, D., Ţurcaş, G.C: Một phương trình Diophantine elliptic từ nghiên cứu các phân vùng. Đinh tán. Univ. Toán Babeş-Bolyai. 70(3), 349–356 (2019)

Bagdasar, O., Andrica, D.: Các kết quả và phỏng đoán mới về 2 phân vùng của multisets. Kỷ yếu của ICMSAO’17 lần thứ 7, IEEE, trang 1–5 (2017)

Bender, E.A: Các phần của multisets. Đĩa đệm. Môn Toán. 9, 301–311 (1974)

Bender, E.A., Devitt, J.S., Richmond, L.S.: Các phần của multisets II. Đĩa đệm. Môn Toán. 50, 1–8 (1984)

Erdös, P.: Trên một bằng chứng cơ bản của một số công thức tiệm cận trong lý thuyết phân vùng. Ann. Môn Toán. 43(2), 437–450 (1942)

Garey, M.R., Johnson, D.S: Kết quả phức tạp cho việc lập lịch trình đa xử lý trong điều kiện hạn chế về tài nguyên. SIAM J. Tính toán. 4, 397–411 (1975)

Garey, M.R., Johnson, D.S.: Máy tính và khả năng tương tác Hướng dẫn về lý thuyết NP-Completeness. Freeman, San Francisco (1979)

Pak, I: Tiểu sử phân vùng, một cuộc khảo sát. Ramanujan J. 12, 5–75 (2006)

Sloane, N.J.A: The On-Line Encyclopedia of Integer Sequences. https://oeis.org

Stanley, R.P .: Nhóm Weyl, định lý Lefschetz cứng và tính chất Sperner. SIAM J. Algebr. Đĩa đệm. Phương pháp 1, 168–184 (1980)

Sullivan, B.D: Theo phỏng đoán của Andrica và Tomescu. J. Số nguyên Seq. 16, Điều 13.3.1 (2013)

Wilf, H.: Công nghệ tạo lập. Báo chí học thuật, New York (1994)


Cách dễ nhất để giới thiệu ccc là hiển thị các phép tính ví dụ khác nhau từ dòng lệnh.

ccc luôn được gọi theo cách sau:

Trong tất cả các ví dụ dưới đây, hãy lưu ý mức độ dễ dàng để diễn đạt các ràng buộc mà nếu không thì đòi hỏi phải viết mã phức tạp hoặc thực hiện số học lặp đi lặp lại trên giấy.

Bốc thăm

ccc có thể cho bạn biết xác suất chọn số lượng mục cụ thể từ một bộ sưu tập (có hoặc không có thay thế).

  • 3 viên bi đỏ (: red_circle :: red_circle :: red_circle :)
  • 5 viên bi đen (: black_circle :: black_circle :: black_circle :: black_circle :: black_circle :)
  • 7 viên bi xanh (: large_blue_circle :: large_blue_circle :: large_blue_circle :: large_blue_circle :: large_blue_circle :: large_blue_circle :: large_blue_circle :)

Để giải quyết vấn đề này với ccc, chúng ta có thể dễ dàng chỉ định bộ sưu tập chúng tôi rút ra từ, kích thước rút thăm mà chúng tôi thực hiện và bất kỳ ràng buộc trên bốc thăm:

Điều này đặt xác suất chiến thắng (không vẽ viên bi xanh) là 2/39, vì vậy có lẽ chúng tôi sẽ thắng một lần sau mỗi 19 lần thử.

Chú ý việc xác định các ràng buộc dễ dàng như thế nào. Chỉ tên của mặt hàng (màu xanh da trời) và số lượng mong muốn của nó (0). Có thể sử dụng bất kỳ toán tử so sánh nào (==,! =, & Lt, & lt =, & gt, & gt =).

Nếu chúng tôi muốn cho phép thay thế một viên bi sau mỗi lần rút thăm, chúng tôi sẽ thêm cờ --replace.

Chúng tôi có thể chỉ định các ràng buộc phức tạp hơn về những gì chúng tôi muốn rút ra từ túi:

  • cả hai viên bi trắng (: white_circle :: white_circle :),
  • ít nhất 1 viên bi đen (: black_circle:+)

Cơ hội chiến thắng của chúng tôi là 3/119 theo ccc, vì vậy chúng tôi hy vọng sẽ giành chiến thắng khoảng 40 lần thử một lần.

Bạn có thể thấy rằng để thể hiện nhiều ràng buộc trên bản vẽ của chúng tôi, chúng tôi chỉ cần sử dụng dấu phẩy để phân tách chúng.

Cuối cùng, có thể sử dụng hoặc (bất kỳ số lần nào) trong các ràng buộc:

  • 3 viên bi đỏ (: red_circle :: red_circle :: red_circle :) hoặc là
  • 1 viên bi trắng, 1 đen và 1 xanh lam (: white_circle :: black_circle :: large_blue_circle :)

Xác suất là 0.1.

Multisets

Nhiều tập hợp là các tập hợp không có thứ tự (như tập hợp) trong đó một mục có thể xuất hiện nhiều lần.

  • ít hơn 10 quả táo (: green_apple :),
  • ít nhất 5 quả chuối (: banana :),
  • số nho không phải là 13 (: nho :),
  • có số dâu tây là chẵn (: dâu tây :)?

Câu trả lời là 406.

Toán tử modulo (%) được sử dụng ở trên cung cấp cơ sở để giải quyết các vấn đề thay đổi tiền xu, ví dụ:

Đơn vị tiền tệ của Vương quốc Anh có các loại tiền sau:

1p, 2p, 5p, 10p, 20p, 50p, £ 1 (100p) và £ 2 (200p)

Có bao nhiêu cách khác nhau để tạo ra £ 5 bằng cách sử dụng bất kỳ số lượng đồng xu nào?

cf. Dự án Euler vấn đề 31

Câu trả lời được tính trong vòng vài giây sau 6,295,434 những cách khác.

Chúng tôi cũng có thể đưa ra các quy định bổ sung đối với đồng tiền, chẳng hạn như hạn chế số lần đồng xu có thể được sử dụng.

Hoán vị

Hoán vị của các từ có thể được tính như sau:

34650 hoán vị độc đáo của dòng sông / tiểu bang nổi tiếng này.

Còn nếu chúng ta chỉ đếm các hoán vị trong đó các trường hợp của cùng một chữ cái không liền kề nhau thì sao?

Sử dụng ràng buộc 'no_adjacent', câu trả lời sẽ trở lại ngay lập tức dưới dạng 2016. Tốc độ của phép tính này là nhờ vào việc sử dụng Đa thức Larguerre Tổng quát.

Chúng tôi cũng có thể coi các chữ cái là có thể phân biệt được (cờ --tên-riêng) để giải quyết một loại vấn đề liên quan:

Năm cặp đôi sẽ ngồi trong một hàng. Có bao nhiêu cách để họ có thể ngồi như vậy mà không có cặp đôi nào được ngồi cùng nhau?

1,263,360 các cách.

ccc cho phép đếm các biến vị (hoán vị mà không có mục nào chiếm vị trí ban đầu của nó).

Năm cặp đôi vẽ tên từ một chiếc mũ. Xác suất mà không ai vẽ tên của chính họ hoặc tên của đối tác của họ là gì?

Hóa ra chỉ có một 0.121 xác suất của điều này xảy ra.

Trình tự

Chuỗi là bộ sưu tập các mục có thứ tự.

Bạn có thể tạo bao nhiêu chuỗi ký tự 30 chữ cái bằng cách sử dụng không quá 20 mỗi chuỗi A, BC?

Câu trả lời là rất nhiều: có 205,863,750,414,990 trình tự như vậy.


3.7: Đếm nhiều bộ

Mô-đun này triển khai các kiểu dữ liệu vùng chứa chuyên biệt cung cấp các lựa chọn thay thế cho các vùng chứa tích hợp sẵn cho mục đích chung của Python,: class: `dict`,: class:` list`,: class: `set` và: class:` tuple`.

: func: `nametuple` chức năng nhà máy để tạo các lớp con tuple với các trường được đặt tên
: class: `deque` vùng chứa giống danh sách với các phần phụ nhanh và bật lên ở hai đầu
: class: `ChainMap` lớp giống dict để tạo một chế độ xem duy nhất của nhiều ánh xạ
: class: `Counter` lớp con dict để đếm các đối tượng có thể băm
: class: `OrderDict` lớp con dict ghi nhớ các mục nhập đơn hàng đã được thêm vào
: class: `defaultdict` lớp con dict gọi một hàm gốc để cung cấp các giá trị bị thiếu
: class: `UserDict` bao bọc xung quanh các đối tượng từ điển để phân lớp con dict dễ dàng hơn
: class: `UserList` bao bọc xung quanh các đối tượng danh sách để phân lớp danh sách con dễ dàng hơn
: class: `UserString` bao bọc xung quanh các đối tượng chuỗi để phân lớp chuỗi dễ dàng hơn

A: class: Lớp `ChainMap` được cung cấp để liên kết nhanh chóng một số ánh xạ để chúng có thể được coi như một đơn vị duy nhất. Nó thường nhanh hơn nhiều so với việc tạo một từ điển mới và chạy nhiều: meth: `

Lớp có thể được sử dụng để mô phỏng các phạm vi lồng nhau và rất hữu ích trong việc tạo khuôn mẫu.

A: class: `ChainMap` nhóm nhiều vùng hoặc các ánh xạ khác với nhau để tạo ra một chế độ xem duy nhất, có thể cập nhật. Nếu không bản đồ được chỉ định, một từ điển trống duy nhất được cung cấp để một chuỗi mới luôn có ít nhất một ánh xạ.

Các ánh xạ cơ bản được lưu trữ trong một danh sách. Danh sách đó là công khai và có thể được truy cập hoặc cập nhật bằng cách sử dụng bản đồ thuộc tính. Không có trạng thái nào khác.

Tra cứu tìm kiếm các ánh xạ cơ bản liên tiếp cho đến khi tìm thấy khóa. Ngược lại, ghi, cập nhật và xóa chỉ hoạt động trên ánh xạ đầu tiên.

A: class: `ChainMap` kết hợp các ánh xạ bên dưới bằng cách tham chiếu. Vì vậy, nếu một trong các ánh xạ cơ bản được cập nhật, những thay đổi đó sẽ được phản ánh trong: class: `ChainMap`.

Tất cả các phương pháp từ điển thông thường đều được hỗ trợ. Ngoài ra, có một bản đồ thuộc tính, một phương thức để tạo các điều kiện con mới và một thuộc tính để truy cập tất cả trừ ánh xạ đầu tiên:

Lưu ý, thứ tự lặp lại của a: class: `ChainMap ()` được xác định bằng cách quét các ánh xạ từ cuối đến đầu tiên:

Điều này cung cấp cùng một thứ tự như một loạt các lệnh gọi: meth: `dict.update` bắt đầu với ánh xạ cuối cùng:

Phần này trình bày các cách tiếp cận khác nhau để làm việc với bản đồ chuỗi.

Ví dụ về mô phỏng chuỗi tra cứu nội bộ của Python:

Ví dụ về việc cho phép các đối số dòng lệnh do người dùng chỉ định được ưu tiên hơn các biến môi trường lần lượt được ưu tiên hơn các giá trị mặc định:

Các mẫu ví dụ để sử dụng lớp: class: `ChainMap` để mô phỏng các ngữ cảnh lồng nhau:

Lớp: class: `ChainMap` chỉ thực hiện cập nhật (ghi và xóa) cho ánh xạ đầu tiên trong chuỗi trong khi các tra cứu sẽ tìm kiếm toàn chuỗi. Tuy nhiên, nếu bạn muốn ghi và xóa sâu, có thể dễ dàng tạo một lớp con cập nhật các khóa được tìm thấy sâu hơn trong chuỗi:

Một công cụ truy cập được cung cấp để hỗ trợ tính năng thuận tiện và nhanh chóng. Ví dụ:

A: class: `Counter` là một lớp con: class:` dict` để đếm các đối tượng có thể băm. Nó là một tập hợp trong đó các phần tử được lưu trữ dưới dạng khóa từ điển và số lượng của chúng được lưu trữ dưới dạng giá trị từ điển. Số đếm được phép là bất kỳ giá trị nguyên nào bao gồm cả số 0 hoặc số âm. Lớp: class: `Counter` tương tự như các bag hoặc multisets trong các ngôn ngữ khác.

Các phần tử được tính từ một có thể lặp lại hoặc được khởi tạo từ một lập bản đồ (hoặc bộ đếm):

Các đối tượng bộ đếm có giao diện từ điển ngoại trừ việc chúng trả về số 0 cho các mục bị thiếu thay vì tăng a: exc: `KeyError`:

Đặt số đếm thành 0 không xóa một phần tử khỏi bộ đếm. Sử dụng del để xóa hoàn toàn:

Đối tượng bộ đếm hỗ trợ ba phương pháp ngoài những phương pháp có sẵn cho tất cả các từ điển:

Các phương thức từ điển thông thường có sẵn cho các đối tượng: class: `Counter` ngoại trừ hai đối tượng hoạt động khác nhau đối với bộ đếm.

Các mẫu phổ biến để làm việc với: class: `Counter` object:

Một số phép toán được cung cấp để kết hợp các đối tượng: class: `Counter` để tạo ra nhiều bộ (bộ đếm có số đếm lớn hơn 0). Phép cộng và phép trừ kết hợp các bộ đếm bằng cách cộng hoặc trừ số đếm của các phần tử tương ứng. Giao điểm và kết hợp trả về số đếm tối thiểu và tối đa tương ứng. Mỗi thao tác có thể chấp nhận đầu vào có số đếm có dấu, nhưng đầu ra sẽ loại trừ các kết quả có số đếm bằng 0 hoặc ít hơn.

Phép cộng và phép trừ một bậc là các phím tắt để thêm một bộ đếm trống hoặc trừ từ một bộ đếm trống.

Bộ đếm chủ yếu được thiết kế để làm việc với các số nguyên dương để biểu thị số đếm đang chạy, tuy nhiên, cần chú ý để không loại trừ các trường hợp sử dụng cần các loại khác hoặc giá trị âm một cách không cần thiết. Để trợ giúp với những trường hợp sử dụng đó, phần này ghi lại các giới hạn về phạm vi và loại tối thiểu.

  • Bản thân lớp: class: `Counter` là một lớp con từ điển không có giới hạn về khóa và giá trị của nó. Các giá trị được dự định là số đại diện cho số đếm, nhưng bạn có thể lưu trữ bất kỳ thứ gì trong trường giá trị.
  • The: meth: `

Trả về một đối tượng deque mới được khởi tạo từ trái sang phải (sử dụng: meth: `append`) với dữ liệu từ có thể lặp lại. Nếu có thể lặp lại không được chỉ định, deque mới trống.

Deques là một tổng quát của ngăn xếp và hàng đợi (tên được phát âm là "bộ bài" và viết tắt của "hàng đợi kết thúc kép"). Deques hỗ trợ an toàn luồng, gắn và bật hiệu quả bộ nhớ từ hai bên của deque với hiệu suất xấp xỉ O (1) ở cả hai hướng.

Mặc dù: các đối tượng class: `list` hỗ trợ các hoạt động tương tự, chúng được tối ưu hóa cho các hoạt động có độ dài cố định nhanh và phải chịu chi phí di chuyển bộ nhớ O (n) cho các hoạt động pop (0) và insert (0, v) thay đổi cả kích thước và vị trí của biểu diễn dữ liệu cơ bản.

Nếu maxlen không được chỉ định hoặc là Không, deques có thể phát triển đến độ dài tùy ý. Nếu không, deque được giới hạn với độ dài tối đa được chỉ định. Khi chiều dài giới hạn đầy đủ, khi các mục mới được thêm vào, một số mục tương ứng sẽ bị loại bỏ khỏi đầu đối diện. Độ dài giới hạn deques cung cấp chức năng tương tự như bộ lọc đuôi trong Unix. Chúng cũng hữu ích để theo dõi các giao dịch và các nhóm dữ liệu khác, nơi chỉ hoạt động gần đây nhất được quan tâm.

Đối tượng Deque hỗ trợ các phương pháp sau:

Đối tượng Deque cũng cung cấp một thuộc tính chỉ đọc:

Ngoài những điều trên, deques hỗ trợ lặp lại, pickling, len (d), reverse (d), copy.copy (d), copy.deepcopy (d), kiểm tra tư cách thành viên với toán tử: keyword: `in` và subscript tham chiếu chẳng hạn như d [-1]. Truy cập được lập chỉ mục là O (1) ở cả hai đầu nhưng chậm lại là O (n) ở giữa. Để truy cập ngẫu nhiên nhanh, hãy sử dụng danh sách để thay thế.

Bắt đầu từ phiên bản 3.5, deques hỗ trợ __add __ (), __mul __ () và __imul __ ().

Phần này trình bày các cách tiếp cận khác nhau để làm việc với deques.

Các deques độ dài được giới hạn cung cấp chức năng tương tự như bộ lọc đuôi trong Unix:

Một cách tiếp cận khác để sử dụng deques là duy trì một chuỗi các phần tử được thêm gần đây bằng cách thêm vào bên phải và xuất hiện ở bên trái:

Một bộ lập lịch vòng lặp có thể được thực hiện với các trình vòng lặp đầu vào được lưu trữ trong một: class: `deque`. Giá trị được tạo ra từ trình lặp hoạt động ở vị trí số không. Nếu trình lặp đó đã hết, nó có thể bị xóa bằng: meth: `

deque.popleft` nếu không, nó có thể được quay trở lại cuối bằng: meth: `

Phương thức deque.rotate` cung cấp một cách để thực hiện: lớp: cắt và xóa `deque`. Ví dụ: một triển khai Python thuần túy của del d [n] dựa vào phương thức xoay () để định vị các phần tử sẽ được bật lên:

Để thực hiện: class: `deque` slice, hãy sử dụng một cách tiếp cận tương tự áp dụng: meth:`

deque.rotate` để đưa một phần tử đích sang bên trái của deque. Xóa các mục cũ bằng: meth: `

deque.extend`, và sau đó đảo ngược vòng quay. Với các biến thể nhỏ trong cách tiếp cận đó, có thể dễ dàng thực hiện các thao tác xếp chồng kiểu Forth như nhân đôi, thả, hoán đổi, qua, chọn, thối và cuộn.

defaultdict.default_factory`, thật dễ dàng nhóm một chuỗi các cặp khóa-giá trị vào một danh sách từ điển:

Khi mỗi khóa được gặp lần đầu tiên, nó chưa có trong ánh xạ nên một mục được tạo tự động bằng cách sử dụng: attr: `

defaultdict.default_factory` hàm trả về một rỗng: class: `list`. Thao tác: meth: `list.append` sau đó gắn giá trị vào danh sách mới. Khi gặp lại các khóa, việc tra cứu vẫn tiến hành bình thường (trả về danh sách cho khóa đó) và thao tác: meth: `list.append` thêm một giá trị khác vào danh sách. Kỹ thuật này đơn giản và nhanh hơn một kỹ thuật tương đương bằng cách sử dụng: meth: `dict.setdefault`:

defaultdict.default_factory` thành: class: `int` làm cho: class:` defaultdict` hữu ích để đếm (giống như một túi hoặc nhiều bộ ở các ngôn ngữ khác):

Khi một chữ cái gặp lần đầu tiên, nó bị thiếu trong ánh xạ, vì vậy: attr: `

defaultdict.default_factory` hàm gọi: func: `int` để cung cấp số lượng mặc định là 0. Sau đó, hoạt động tăng dần sẽ tích lũy số lượng cho mỗi chữ cái.

Hàm: func: `int` luôn trả về 0 chỉ là một trường hợp đặc biệt của hàm hằng. Một cách nhanh hơn và linh hoạt hơn để tạo các hàm hằng là sử dụng một hàm lambda có thể cung cấp bất kỳ giá trị không đổi nào (không chỉ bằng 0):

: func: `nametuple` Factory Chức năng dành cho Tuples với các trường được đặt tên

Các bộ giá trị được đặt tên chỉ định ý nghĩa cho từng vị trí trong một bộ mã và cho phép mã tự ghi lại, dễ đọc hơn. Chúng có thể được sử dụng ở bất cứ nơi nào sử dụng các bộ giá trị thông thường và chúng thêm khả năng truy cập các trường theo tên thay vì chỉ mục vị trí.

Các bộ giá trị được đặt tên đặc biệt hữu ích để gán tên trường cho các bộ giá trị kết quả được trả về bởi: mod: `csv` hoặc: mod:` sqlite3` mô-đun:

Ngoài các phương thức được kế thừa từ các bộ giá trị, các bộ giá trị được đặt tên hỗ trợ thêm ba phương thức và hai thuộc tính. Để tránh xung đột với tên trường, tên phương thức và thuộc tính bắt đầu bằng dấu gạch dưới.

Để truy xuất một trường có tên được lưu trữ trong một chuỗi, hãy sử dụng hàm: func: `getattr`:

Để chuyển đổi một từ điển thành một tuple được đặt tên, hãy sử dụng toán tử ** (như được mô tả trong: ref: `tut-unacking-objects`):

Vì tuple được đặt tên là một lớp Python thông thường, nên dễ dàng thêm hoặc thay đổi chức năng với một lớp con. Đây là cách thêm trường được tính toán và định dạng in có chiều rộng cố định:

Lớp con được hiển thị ở trên đặt __slots__ thành một bộ giá trị trống. Điều này giúp giữ cho yêu cầu bộ nhớ ở mức thấp bằng cách ngăn chặn việc tạo từ điển phiên bản.

Phân lớp không hữu ích cho việc thêm các trường mới, được lưu trữ. Thay vào đó, chỉ cần tạo một loại tuple mới được đặt tên từ: attr: `

Các chuỗi tài liệu có thể được tùy chỉnh bằng cách gán trực tiếp cho các trường __doc__:

Giá trị mặc định có thể được thực hiện bằng cách sử dụng: meth: `

somenametuple._replace` để tùy chỉnh một phiên bản nguyên mẫu:

Từ điển có thứ tự cũng giống như từ điển thông thường nhưng có thêm một số tính năng liên quan đến hoạt động sắp xếp. Bây giờ chúng đã trở nên ít quan trọng hơn khi lớp tích hợp sẵn: class: `dict` có được khả năng ghi nhớ thứ tự chèn (hành vi mới này đã được đảm bảo trong Python 3.7).

Một số khác biệt so với: class: `dict` vẫn còn:

  • Lớp thông thường: class: `dict` được thiết kế để rất tốt trong các hoạt động ánh xạ. Theo dõi thứ tự chèn là thứ yếu.
  • : Class: `OrderedDict` được thiết kế để có thể sắp xếp lại các thao tác tốt. Hiệu quả không gian, tốc độ lặp lại và hiệu suất của các hoạt động cập nhật chỉ là thứ yếu.
  • Về mặt thuật toán,: class: `OrderedDict` có thể xử lý các hoạt động sắp xếp lại thường xuyên tốt hơn so với: class:` dict`. Điều này làm cho nó phù hợp để theo dõi các truy cập gần đây (ví dụ: trong bộ nhớ cache LRU).
  • Phép toán bình đẳng cho: class: `OrderedDict` kiểm tra để khớp lệnh.
  • Phương thức: meth: `popitem` của: class:` OrderedDict` có một chữ ký khác. Nó chấp nhận một đối số tùy chọn để chỉ định mục nào được xuất hiện. có phương thức: meth: `move_to_end` để định vị lại một cách hiệu quả một phần tử thành một điểm cuối.
  • Cho đến Python 3.8,: class: `dict` thiếu phương thức: meth:` __reversed__`.

Trả về một thể hiện của lớp con: class: `dict` có các phương thức chuyên dùng để sắp xếp lại thứ tự từ điển.

Ngoài các phương pháp ánh xạ thông thường, các từ điển có thứ tự cũng hỗ trợ lặp lại đảo ngược bằng cách sử dụng: func: `reverseed`.

Kiểm tra tính bình đẳng giữa các đối tượng: class: `OrderedDict` có phân biệt thứ tự và được triển khai dưới dạng list (od1.items ()) == list (od2.items ()). Kiểm tra tính bình đẳng giữa các đối tượng: class: `OrderedDict` và các đối tượng khác: class:`

Các đối tượng collection.abc.Mapping` không phân biệt thứ tự như các từ điển thông thường. Điều này cho phép các đối tượng: class: `OrderedDict` được thay thế ở bất kỳ nơi nào mà từ điển thông thường được sử dụng.

Thật dễ dàng để tạo một biến thể từ điển có thứ tự ghi nhớ thứ tự của các khóa Cuối cùng được chèn vào. Nếu mục nhập mới ghi đè mục nhập hiện có, vị trí chèn ban đầu sẽ được thay đổi và chuyển đến cuối:

An: class: `OrderedDict` cũng sẽ hữu ích cho việc triển khai các biến thể của: func:` functools.lru_cache`:

Lớp,: class: `UserDict` hoạt động như một trình bao bọc xung quanh các đối tượng từ điển. Nhu cầu về lớp này đã được thay thế một phần bởi khả năng phân lớp trực tiếp từ: class: `dict` tuy nhiên, lớp này có thể dễ làm việc hơn vì từ điển bên dưới có thể truy cập được dưới dạng một thuộc tính.

Lớp mô phỏng một từ điển. Nội dung của cá thể được lưu giữ trong một từ điển thông thường, có thể truy cập được thông qua thuộc tính: attr: `data` của: cá thể class:` UserDict`. Nếu dữ liệu ban đầu được cung cấp,: attr: `data` được khởi tạo với nội dung của nó lưu ý rằng một tham chiếu đến dữ liệu ban đầu sẽ không được lưu giữ, cho phép nó được sử dụng cho các mục đích khác.

Ngoài việc hỗ trợ các phương thức và hoạt động của ánh xạ, các thể hiện: class: `UserDict` cung cấp thuộc tính sau:

Lớp này hoạt động như một trình bao bọc xung quanh các đối tượng danh sách. Nó là một lớp cơ sở hữu ích cho các lớp giống như danh sách của riêng bạn, lớp này có thể kế thừa từ chúng và ghi đè các phương thức hiện có hoặc thêm các phương thức mới. Bằng cách này, người ta có thể thêm các hành vi mới vào danh sách.

Nhu cầu về lớp này đã được thay thế một phần nhờ khả năng phân lớp trực tiếp từ: class: `list` tuy nhiên, lớp này có thể dễ làm việc hơn vì danh sách cơ bản có thể truy cập được dưới dạng một thuộc tính.

Lớp mô phỏng một danh sách. Nội dung của cá thể được giữ trong một danh sách thông thường, có thể truy cập được thông qua thuộc tính: attr: `data` của: cá thể class:` UserList`. Nội dung của phiên bản ban đầu được đặt thành một bản sao của danh sách, mặc định là danh sách trống []. danh sách có thể là bất kỳ có thể lặp lại nào, ví dụ: một danh sách Python thực hoặc một đối tượng: class: `UserList`.

Ngoài việc hỗ trợ các phương thức và hoạt động của chuỗi có thể thay đổi, các trường hợp: class: `UserList` cung cấp thuộc tính sau:

Yêu cầu về phân lớp: Subclasses of :class:`UserList` are expected to offer a constructor which can be called with either no arguments or one argument. List operations which return a new sequence attempt to create an instance of the actual implementation class. To do so, it assumes that the constructor can be called with a single parameter, which is a sequence object used as a data source.

If a derived class does not wish to comply with this requirement, all of the special methods supported by this class will need to be overridden please consult the sources for information about the methods which need to be provided in that case.

The class, :class:`UserString` acts as a wrapper around string objects. The need for this class has been partially supplanted by the ability to subclass directly from :class:`str` however, this class can be easier to work with because the underlying string is accessible as an attribute.

Class that simulates a string object. The instance's content is kept in a regular string object, which is accessible via the :attr:`data` attribute of :class:`UserString` instances. The instance's contents are initially set to a copy of seq. Các seq argument can be any object which can be converted into a string using the built-in :func:`str` function.

In addition to supporting the methods and operations of strings, :class:`UserString` instances provide the following attribute:


3.7: Counting Multisets

A solution by BSI Problems Group, Bomm, Germanny, appeared in Monthly 117, October 2010, pp.747-748 without references to either P. Erdös, R. Honsberger, or S. Savchev.

We recursively construct multisets Am and Bm of size 2 m for For such m, choose arbitrary positive cm. Let and For let and Inductively, and Also which yields

Claim 1 : a2 + a3 &trong <>3,. Sn(n-1)/2>. Since a1 + a2 &le a1 + a3 &le a2 + a3, we have Also, the only sums that can be strictly smaller than are Thus

Claim 2 : Let B = <>1,. bn> with b1 &le b2 &le . &le bn. If and then We prove that by induction on i. Let and If then and are both minimal among S(A) - S(A(i - 1)). Như vậy

Claim 3 : Let B = <>1,. bn> with b1 &le . &le bn. If and then Since the two smallest sums from the two sets are equal, and With the hypothesis we have Claim 2 now applies.

Given these claims, let A 1 , . A n-1 be multisets of size n having the same sumset. Write A k = <>1 (k) , . an (k) > with a1 (k) &le . &le an (k) . By Claim 1, there are at most n - 2 values for the sum of the second and third smallest elements. By the pigeonhole principle, there exist distinct k and m such that By Claim 3, Thus at most n - 2 multisets can have the same sumset.

Câu trả lời là có. Let A = <0, 4, 4, 4, 6, 6, 6, 10>, B = <2, 2, 2, 4, 6, 8, 8, 8, >, and C = <1, 3, 3, 3, 7, 7, 7, 9>. With exponents denoting multiplicity, S(A), S(B), and S(C) all equal <4 (3) , 6 (3) , 8 (3) , 10 (10) , 12 (3) , 14 (3) , 16 (3) >.

Note : The GCHQ Problem Solving Group solved part (a) by letting A1 be the set of nonnegative integers less than 2n whose binary expansion has an even number of ones and setting A2 = <0, 1, 2, . 2n - 1>- A1. This results from the construction given above by setting

For part (c), Daniele Degiorgi gave the example A = <0, 6, 7, 9, 11, 13, 14, 20>, B = <1, 5, 6, 8, 12, 14, 15, 19>, and C = <2, 4, 5, 9, 11, 15, 16, 18>, showing that it can be solved with sets (i.e., multisets with no repeated elements).

It remains open whether there are quadruples of multisets of size greater than 2 with the same sumset, or whether there are triples of multisets of any size greater than 2 other than 8 with the same sumset. Richard Stong showed that the search for such triples can be restricted to multisets whose size is an odd power of 2.