Tổng quát mảng Riffle


22

Một sân golf đơn giản để bắt đầu tuần mới! Bạn được cung cấp ba mảng: mảng cơ sở B , mảng giá trị Vmảng chỉ mục I . Bạn nên tạo một mảng khác trong đó các giá trị từ Vđược chèn vào Btại các chỉ mục được chỉ định bởi I. Đây là một ví dụ:

Base:    [5, 1, 4, 1, 3]
Values:  [0, 0, 7]
Indices: [5, 0, 3]

Các chỉ số tại các vị trí sau trong mảng cơ sở:

[ 5, 1, 4, 1, 3 ]
 ^        ^    ^
 0        3    5

Vì vậy, chèn các phần tử tương ứng từ mảng giá trị, kết quả sẽ là:

[0, 5, 1, 4, 7, 1, 3, 0]

Quy tắc

Bạn có thể viết chương trình hoặc hàm, lấy đầu vào qua STDIN (hoặc thay thế gần nhất), đối số dòng lệnh hoặc đối số hàm và xuất kết quả qua STDOUT (hoặc thay thế gần nhất), giá trị trả về của hàm hoặc bằng cách sửa đổi mảng được cung cấp làm Btham số .

Nếu trình của bạn là một chức năng IVcó thể được sửa đổi theo bất kỳ cách nào, cũng như Bnếu nó không được sử dụng cho đầu ra.

Bạn có thể đưa ra các giả định sau về đầu vào:

  • Tất cả các phần tử của mảng cơ sở và giá trị sẽ là các số nguyên không âm.
  • Mảng giá trị sẽ có nhiều nhất một phần tử so với mảng cơ sở.
  • Mảng giá trị và mảng chỉ mục sẽ có cùng số phần tử.
  • Mảng chỉ mục sẽ không chứa các chỉ mục lặp lại và tất cả các chỉ mục sẽ nằm trong phạm vi.
  • Các mảng cơ sở và giá trị có thể chứa các phần tử lặp lại.
  • Bất kỳ hoặc tất cả các mảng có thể trống.
  • Bạn không được cho rằng các chỉ số được đưa ra theo bất kỳ thứ tự cụ thể nào.
  • Bạn có thể nhận đầu vào và sản xuất đầu ra ở bất kỳ định dạng danh sách hoặc chuỗi thuận tiện, rõ ràng nào. Bạn cũng có thể chọn nhận ba mảng theo thứ tự khác nhau.
  • Bạn có thể chọn giữa lập chỉ mục dựa trên 0 và 1 dựa trên.

Đây là mã golf, vì vậy câu trả lời ngắn nhất (tính bằng byte) sẽ thắng.

Các trường hợp thử nghiệm

Đưa ra trong định dạng B V I => Resultcho lập chỉ mục dựa trên 0. Nếu bạn đang sử dụng lập chỉ mục dựa trên 1, hãy tăng các phần tử của mảng thứ ba lên 1.

[] [] [] => []
[] [1] [0] => [1]
[1,2] [] [] => [1,2]
[1,2] [3] [0] => [3,1,2]
[1,2] [3] [1] => [1,3,2]
[1,2] [3] [2] => [1,2,3]
[0,0,0] [1,1,1,1] [0,1,2,3] => [1,0,1,0,1,0,1]
[5,1,4,1,3] [0,0,7] [5,0,3] => [0,5,1,4,7,1,3,0]
[1,2,3,4] [4,3,2,1] [4,0,3,1] => [3,1,1,2,3,2,4,4]

Hãy cho tôi biết nếu bạn gặp các trường hợp cạnh thú vị khác, và tôi sẽ thêm chúng.

Bảng xếp hạng

Dưới đây là Stack Snippet để tạo cả bảng xếp hạng thông thường và tổng quan về người chiến thắng theo ngôn ngữ.

Để đảm bảo rằng câu trả lời của bạn hiển thị, vui lòng bắt đầu câu trả lời của bạn bằng một tiêu đề, sử dụng mẫu Markdown sau:

# Language Name, N bytes

nơi Nlà kích thước của trình của bạn. Nếu bạn cải thiện điểm số của mình, bạn có thể giữ điểm số cũ trong tiêu đề, bằng cách đánh bại chúng thông qua. Ví dụ:

# Ruby, <s>104</s> <s>101</s> 96 bytes


4
Bạn cảm thấy thế nào về NULLmột mảng trống cho các ngôn ngữ có một mảng trống NULL?
Alex A.

@AlexA. Nếu đó là một phổ biến / các đại diện của các mảng sản phẩm nào trong ngôn ngữ nói (s), tôi vẫn ổn với điều đó.
Martin Ender

3
Một sân golf đơn giản ? Đó là điều khó khăn nhất tôi đã làm ở CJam cả tuần. : P
Dennis

Câu trả lời:


13

Bình thường, 14 byte

s.icFPQmedSCtQ

Trình diễn.

Chương trình này lấy các đầu vào dưới dạng 3 tuple danh sách theo thứ tự Cơ sở, Chỉ số, Giá trị.

Giải thích về ví dụ [5, 1, 4, 1, 3], [5, 0, 3], [0, 0, 7]:

  1. Lấy đầu vào: ẩn, Q là đầu vào.

  2. Tạo chỉ số, cặp giá trị: CtQ=[(5, 0), (0, 0), (3, 7)]

  3. Sắp xếp các cặp theo thứ tự chỉ số tăng dần: SCtQ=[(0, 0), (3, 7), (5, 0)]

  4. Lấy giá trị ra khỏi mỗi cặp: medSCtQ=[0, 7, 0]

  5. Chia danh sách cơ sở tại vị trí của các chỉ dẫn: cFPQ =[[], [5, 1, 4], [1, 3], []]

  6. Xen kẽ 3 và 4: .icFPQmedSCtQ =[[], 0, [5, 1, 4], 7, [1, 3], 0, []]

  7. Kết hợp thành một danh sách: s.icFPQmedSCtQ=[0, 5, 1, 4, 7, 1, 3, 0]


Chỉ trích. Từ khi nào chúng ta có một phương pháp xen kẽ? Chỉ muốn đăng bài ssC,cFPQamedSCtQ].
Jakube

5
@Jakube isaac lén lút cam kết trong 6 ngày trước.
orlp


3
@Jakube kể từ khi Pyth có thể phát triển để giải quyết bất kỳ vấn đề. Đó là vấn đề với ngôn ngữ chơi gôn. Ngôn ngữ bí truyền tồn tại vì lợi ích của ngôn ngữ bí truyền; như chúng được thiết kế * sau đó
sentiao

@sentiao Công bằng mà nói, ngôn ngữ máy chủ (Python) đã xen kẽ dưới một tên khác trong một thời gian.
Mego

16

Con trăn 2, 54

lambda B,*X:map(B.insert,*zip(*sorted(zip(*X))[::-1]))

Đưa đầu vào là B,I,V . Sửa đổi đầu vào Bkhi được gọi (cảm ơn Martin Büttner đã nhắc nhở tôi điều này là có thể).

Sử dụng mapđể gọi B.inserttrên mỗi cặp chỉ số / yếu tố. Để tránh sự cố của các chỉ mục danh sách dịch chuyển khi các phần tử được chèn, hãy sắp xếp các cặp theo thứ tự giảm chỉ số theo một zip / sort / unzip xấu xí. Nếu không phải là vấn đề thay đổi, chúng ta có thể làm map(B.insert,*X).

Phương pháp cũ (65):

B,V,I=input()
for i,v in sorted(zip(I,V))[::-1]:B[i:i]=v,
print B

5

Haskell, 62 byte

import Data.List
f b v i=map snd$sort$zip[0.5,1.5..]b++zip i v

Ví dụ sử dụng: f [5,1,4,1,3] [0,0,7] [5,0,3]-> [0,5,1,4,7,1,3,0].

Cách thức hoạt động: tăng danh sách cơ sở với các chỉ số "và một nửa" bắt đầu từ 0.5(ví dụ [(0.5,5),(1.5,1),(2.5,4),(3.5,1),(4.5,3)]) và nối nó với các cặp giá trị chỉ số. Sắp xếp và loại bỏ chỉ mục.

Ghi chú : không biết nếu tôi gian lận ở đây. Từ quan điểm toán học thì tốt, nhưng một lập trình viên có thể lập luận rằng danh sách các chỉ số [5,0,3]không phải là danh sách Integerstheo yêu cầu, mà là một danh sách Fractionals(chính xác, loại là đa hình, nhưng phải thuộc về Fractionallớp, ví dụ Floathoặc Double).


5

Ruby, 60 59 53 byte

->a,b,c{c.zip(b).sort.reverse.map{|i,v|a.insert i,v}}

Và phiên bản không có người nhận

def riffle(array, values, indices)
    indices.zip(values).sort.reverse.each do |index, value|
        array.insert(index, value)
    end
end

2
Bạn có thể rút ngắn điều này bằng cách biến nó thành một hàm không tên thay thế : ->a,b,c{...}. Ngoài ra cơ hội là insertkhông cần dấu ngoặc đơn.
Martin Ender

@ MartinBüttner Tôi đã biết về chức năng chưa được đặt tên với lambda, nhưng tôi không cảm thấy đó là tinh thần của thách thức (thường yêu cầu một chức năng được đặt tên). Cảm ơn vì đã phát hiện ra các parens.
Dylan Frese 19/05/2015

Trừ khi thách thức đặc biệt yêu cầu một chức năng được đặt tên, các chức năng không tên luôn được chấp nhận . Và tôi đã không yêu cầu một chức năng được đặt tên (tôi không bao giờ làm;)).
Martin Ender

5

CJam, 34 23 18 byte

{.\2/\ee+{0=}$1f=}

Đệ trình CJam đầu tiên của tôi. Lời khuyên được chào đón, tôi chắc chắn có rất nhiều thứ để chơi gôn.

16 byte được lưu với sự trợ giúp của @ MartinBüttner và @Dennis.

Chức năng mong đợi đầu vào trên ngăn xếp theo thứ tự B V I (I là trên cùng).

Ví dụ sử dụng:

[5 1 4 1 3] [0 0 7] [5 0 3] {.\2/\ee+{0=}$1f=}~

Phương pháp:

  • ghép iphần tử thứ của mảng vớii+0.5
  • ghép giá trị chèn với vị trí chèn
  • hợp nhất hai mảng kết quả
  • sắp xếp mảng dựa trên các yếu tố vị trí
  • giữ các yếu tố giá trị

Cách tiếp cận điểm nổi đó rất thông minh và (đáng buồn) tốt hơn của tôi. Bạn có thể nhận được tới 19 byte với q~.5fm.\2/\ee+$1f=pvà đến 18 byte bằng cách sử dụng chức năng ẩn danh:{.5fm.\2/\ee+$1f=}
Dennis

Cùng một ý tưởng mà không có thủ thuật dấu phẩy động: {.\2/\ee+{0=}$1f=}(vẫn là 18 byte)
Dennis

@Dennis Cảm ơn, tôi không thể tìm thấy get array elementnhà điều hành cho 1f=. Tôi sẽ để nó như một chương trình đầy đủ mặc dù.
ngẫu nhiên

Cuộc gọi của bạn. Bạn có phiền tôi hỏi tại sao bạn phản đối việc đăng một chức năng không?
Dennis

@Dennis Tôi mới bắt đầu CJam và không chắc chắn cách sử dụng các chức năng. Bây giờ tôi đã tìm ra nó để tôi thay đổi câu trả lời cho điều đó.
ngẫu nhiên

5

K, 22 21 byte

{,//+(y@<z;(z@<z)_ x)}

Chúng ta định nghĩa một hàm 3 đối {…}với các biến tiềm ẩn x, yzđại diện cho danh sách khởi động, danh sách giá trị và danh sách chỉ số tương ứng. Toán tử "cắt" ( _) được sử dụng để tách danh sách bắt đầu ra ngoài tại danh sách được sắp xếp của các chỉ số đã cho ( (z@<z)). Chúng tôi xen kẽ các giá trị (sau khi sắp xếp chúng tương ứng) với các phần tách ra của mảng ban đầu bằng cách tạo một danh sách ( (a;b)), lấy transpose ( +) của nó và làm phẳng kết quả (,// ).

Ví dụ sử dụng:

  f:{,//+(y@<z;(z@<z)_ x)}
{,//+(y@<z;(z@<z)_ x)}

  f[1 2 3 4;4 3 2 1;4 0 3 1]
3 1 1 2 3 2 4 4

  f[5 1 4 1 3;0 0 7;5 0 3]
0 5 1 4 7 1 3 0

Không gian xung quanh dấu gạch dưới là cần thiết vì K cho phép dấu gạch dưới trong định danh. K5 loại bỏ sự mơ hồ tiềm năng này. Nếu chúng ta có thể tin tưởng vào các chỉ số sắp xếp theo thứ tự tăng dần và dấu gạch dưới không phải là định danh hợp lệ, chúng ta có thể sử dụng chương trình 13 byte đẹp hơn nhiều:

{,//+(y;z_x)}

(thở dài.)

chỉnh sửa:

{,//+(y@<z;(z@<z)_ x)} / before
{,//+(y@<z;z[<z]_ x)}  / after

Phá vỡ tính đối xứng, nhưng chúng ta có thể lưu một byte bằng cách sử dụng chỉ mục ngoặc ( […]) thay cho toán tử @lập chỉ mục infix . Thông thường, điều này làm cho các chương trình dài hơn, nhưng trong trường hợp này, chúng tôi vẫn cần parens để sắp xếp ztrước khi thực hiện cắt.


4

Bình thường, 17 byte

ssC,cFPQamedSCtQ]

@isaacg đánh bại giải pháp của tôi rồi. Nhưng vì tôi đã hoàn thành tài liệu của mình, tôi sẽ đăng nó đi.

Điều này có đầu vào trong định dạng B, I, V. Bạn có thể thử nó ở đây: Trình diễn hoặc Test Suite

Giải trình:

Tôi đang sử dụng ví dụ B = [5,1,4,1,3], I = [5,0,3], V = [0,0,7]từ OP.

                    implicit: Q = input()
      PQ            all elements but last of Q   => [[5,1,4,1,3], [5,0,3]]
    cF              split B it the indices in I  => [[], [5,1,4], [1,3], []]

              tQ    all elements but first of Q  => [[5,0,3], [0,0,7]]
             C      zip                          => [(5,0), (0,0), (3,7)]
            S       sort                         => [(0,0), (3,7), (5,0)]
         med        extract the end of each pair => [0,7,0]
        a       ]   append an empty list         => [0,7,0,[]]

   ,                create a pair => ([[], [5,1,4], [1,3], []], [0,7,0,[]])
  C                 zip           => [([],0), ([5,1,4],7), ([1,3],0), ([],[])]
 s                  sum           => ([],0,[5,1,4],7,[1,3],0,[],[])
s                   sum           => [0,5,1,4,7,1,3,0]

4

JavaScript (ES6), 75

Một hàm có 3 tham số mảng, trả về một mảng. Thật kỳ lạ, chức năng này sửa đổi itham số của nó (như được OP cho phép)

Kiểm tra chạy đoạn mã, Firefox chỉ như bình thường.

f=(b,v,i,j=0)=>b.concat(v).map(p=>(p=i.indexOf(j))<0?b[j++]:(i[p]=-1,v[p]))

// TEST
out=x=>O.innerHTML+=x+'\n'

test=[
{ b:[], v:[], i:[], k:[] },
{ b:[], v:[1], i:[0], k:[1] },
{ b:[1,2], v:[], i:[], k:[1,2] },
{ b:[1,2], v:[3], i:[0], k:[3,1,2] },
{ b:[1,2], v:[3], i:[1], k:[1,3,2] },
{ b:[1,2], v:[3], i:[2], k:[1,2,3] },
{ b:[0,0,0], v:[1,1,1,1], i:[0,1,2,3], k:[1,0,1,0,1,0,1] },
{ b:[5,1,4,1,3], v:[0,0,7], i:[5,0,3], k:[0,5,1,4,7,1,3,0] },
{ b:[1,2,3,4], v:[4,3,2,1], i:[4,0,3,1], k:[3,1,1,2,3,2,4,4] }
];

test.forEach(x=>{
  r = f(x.b,x.v,x.i.slice(0)) // pass a copy of i, as the function will alter it
  ok = ''+r==''+x.k
  s='Test ' + (ok?'OK':'FAIL')
  +'\n B ['+x.b
  +']\n V ['+x.v
  +']\n I ['+x.i
  +']\n Result ['+r
  +']\n Check  ['+x.k
  +']\n'
  out(s)
  
})
<pre id=O></pre>


Vì tò mò, những gì về mã làm cho nó cụ thể cho Firefox? Có phải vì đó là ES6?
Alex A.

@ AlexA.it là vì ES6, vâng. Đặc biệt, việc fat arrow functionnày không được triển khai ngay cả trong phiên bản dành cho nhà phát triển của Chrome (AFAIK)
edc65

Thật vậy, ngay cả bản dựng Canary của Chrome cũng hỗ trợ nó.
DocMax

4

Toán học, 52 51 byte

Last/@(Tr@#2->#&~MapIndexed~#⋃Thread[#3+.5->#2])&

Thí dụ:

In[1]:= f = Last/@(Tr@#2->#&~MapIndexed~#⋃Thread[#3+.5->#2])&;

In[2]:= f[{5, 1, 4, 1, 3}, {0, 0, 7}, {5, 0, 3}]

Out[2]= {0, 5, 1, 4, 7, 1, 3, 0}

Giải trình:

Sử dụng ví dụ trên.

  • Tr@#2->#&~MapIndexed~# => {1 -> 5, 2 -> 1, 3 -> 4, 4 -> 1, 5 -> 3}
  • Thread[#3+.5->#2] => {5.5 -> 0, 0.5 -> 0, 3.5 -> 7}
  • Sau đó lấy liên kết (sắp xếp) của hai danh sách này. (=> {0.5 -> 0, 1 -> 5, 2 -> 1, 3 -> 4, 3.5 -> 7, 4 -> 1, 5 -> 3, 5.5 -> 0})
  • Và sau đó lấy yếu tố cuối cùng của mỗi cặp. (=> {0, 5, 1, 4, 7, 1, 3, 0})


3

R, 75 byte

function(b,v,i){n=b;j=0;for(g in v)n=append(n,g,i[j<-j+1]+sum(i<i[j])-1);n}

Điều này tạo ra một chức năng không tên. Để gọi nó, đặt tên cho nó, vd f=function.... Lưu ý rằng các mảng phải được lập chỉ mục 1 vì đó chỉ là cách R cuộn.

Ungolfed + giải thích:

f <- function(b, v, i) {
    # Initialize the output vector to b
    n <- b

    # Initialize an index over the indices
    j <- 0

    # Loop over the values to insert
    for(g in v) {
        # Get the index of the next given insertion index
        j <- j + 1

        # Insert g into n.
        # The position at which to insert the value is determined by
        # adding the number of indices less than the current one and
        # subtracting 1. The subtraction is because we're using the
        # `after` argument in the `append` function.

        n <- append(n, g, i[j] + sum(i < i[j]) - 1)
    }

    # Return n
    n
}

Ví dụ:

> f(c(), c(), c())
[1] NULL

> f(c(0, 0, 0), c(1, 1, 1, 1), c(1, 2, 3, 4))
[1] 1 0 1 0 1 0 1

> f(c(5, 1, 4, 1, 3), c(0, 0, 7), c(6, 1, 4))
[1] 0 5 1 4 7 1 3 0

Đề nghị được chào đón như mọi khi!


2

CJam, 19 byte

l~_,)N*q~.{t}~.\N-p

Đây là một chương trình đầy đủ mà đọc các mảng B , IV (một trên mỗi dòng, theo thứ tự đó) từ STDIN.

Hãy thử trực tuyến trong trình thông dịch CJam .

Làm thế nào nó hoạt động

l~    e# Evaluate the first line of input.
_,)   e# Compute the array length and add 1.
N*    e# Push a string of that many linefeeds.
q~    e# Evaluate the remaining input.
.{t}~ e# Vectorized array set: for each index in the array from line 2, replace the
      e# LF at that index by the corresponding element of the array from line 3.
.\    e# Interleave the two arrays on the stack.
N-    e# Remove the linefeeds.
p     e# Print.

CJam, 20 byte

{Qa+@@.{a2$2$=+t}e_}

Đây là một hàm ẩn danh bật B , VI (từ trên xuống dưới) từ ngăn xếp và để lại một mảng duy nhất trên ngăn xếp.

Hãy thử trực tuyến trong trình thông dịch CJam .

Làm thế nào nó hoạt động

Qa+      e# Append [[]] to B.
@@       e# Rotate V and I on top of B.
.{       e# For each v in V and the corresponding i in I:
   a     e#     Push [v].
   2$2$= e#     Retrieve b := B[i].
   +     e#     Append to push [v b].
         e#     The stack now consists of: B i [v b]
   t     e#     Set B[i] := [v b].
}        e#
e_       e# Flatten B.

1

Ruby, 48 byte

Tôi nghĩ rằng điều này tuân thủ các quy tắc, nhưng xin vui lòng kiểm tra.

->b,v,i{l=-1;i.map{|j|b[j]=[v[l+=1],b[j]]};b*?:}

Hàm không tên lấy ba mảng làm đầu vào. Xuất ra một chuỗi có thể được phân tích cú pháp rõ ràng thành một mảng các số có biểu thức rubyx.split(/:+/).map(&:to_i) .

Các trường hợp thử nghiệm trên ideone .

Tôi có thể tiết kiệm thêm 3 byte, nhưng định dạng đầu ra [1,2,[nil,5]]đang kéo dài các quy tắc một chút quá mych imo, mặc dù nó không rõ ràng.


Tôi nghĩ định dạng hiện tại là ổn. Các mảng lồng nhau với các nilgiá trị xen kẽ là một chút kéo dài. Nhưng trong cả hai trường hợp, điều này không chiến thắng trong cuộc thi, vì vậy tôi cũng không thực sự lo lắng về điều đó.
Martin Ender

1

R, 60

Là một hàm không tên có b, v và i

function(b,v,i){e=c(NA,rbind(b,NA));e[i*2+1]=v;e[!is.na(e)]}

Mở rộng b với NA lấp đầy các khoảng trống khi cần với v Trả về vectơ không có NA

> f=function(b,v,i){e=c(NA,rbind(b,NA));e[i*2+1]=v;e[!is.na(e)]}
> f(c(), c(), c())
logical(0)
> f(c(0, 0, 0), c(1, 1, 1, 1), c(0, 1, 2, 3))
[1] 1 0 1 0 1 0 1
> f(c(5, 1, 4, 1, 3), c(0, 0, 7), c(5, 0, 3))
[1] 0 5 1 4 7 1 3 0

1

Java, 253, 226, 219, 209

không chính xác là một người chiến thắng, nhưng oh tốt.

Giả sử rằng B, V và tôi không phải là null. v (chữ thường v) là chiều dài của mảng Giá trị / Ấn. R là mảng trả về. r là chiều dài của mảng trả về. x, y và tôi đều là số nguyên tạm thời.

int[]f(int[]B,int[]V,int[]I){int v=V.length,r=B.length+v,x,y,i;int[]R=java.utils.Arrays.copyOf(B,r);for(x=0;x<v;x++){i=I[x];for(y=0;y<x;y++)if(I[x]>I[y])i++;for(y=r-2;y>=i;y--)R[y+1]=R[y];R[i]=V[x];}return R;}

mở rộng:

int[]f( int[] B, int[] V, int[] I ) {
    int v = V.length, //length of Values
        r = B.length + v, //length of the result
        x, y, i; //temps
        int[] R = java.utils.Arrays.copyOf( B, r );       
        for( x = 0; x < v; x++ ) {
        i = I[x];
        for( y = 0; y < x; y++ )
            if( I[x] > I[y] )
                i++;
        for( y = r - 2; y >= i; y-- )
            R[y+1] = R[y];
        R[i] = V[x];
    }
    return R;
}

1

APL, 22 byte

{(∊⌽2↑⍵)[⍋(2⊃⍵),⍳≢⊃⍵]}

Trong ⎕IO ← 0 để khớp với các trường hợp thử nghiệm.

Đó là một thuật toán tiêu chuẩn: vectơ chỉ mục của đối số đầu tiên được gắn vào các chỉ mục đã cho (đối số thứ 3). tính toán hoán vị sẽ sắp xếp các chỉ mục theo thứ tự tăng dần. Do thuật toán sắp xếp của APL ổn định theo định nghĩa, nên tính toán hoán vị đặt phần tử của catenation của đối số thứ hai và thứ nhất vào đúng vị trí.

Ví dụ :

    {(∊⌽2↑⍵)[⍋(2⊃⍵),⍳≢⊃⍵]}(5 1 4 1 3)(0 0 7)(5 0 3)
0 5 1 4 7 1 3 0
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.