Kim tự tháp chữ

[COCI 2014/2015 - vòng 1, bài 3 - 100/650 điểm]

Đề bài An và Bình là hai bạn thân. Một ngày nọ, hai bạn dùng gạch thẻ xếp thành một kim tự tháp nho nhỏ rồi lấy gạch khắc một từ lên đó, trông như thế này:

# PEPE
    P # ---->
   P E # <----
  E P E # ---->
 E P E P # <----

An lấy K tầng trong kim tự tháp và đố Bình có bao nhiêu kí tự nào đó ở K tầng này. Là anh/chị/cô/chú của Bình, hãy viết chương trình để trả lời câu hỏi “hóc búa” trên.

I/O

  • Input: stdin
    • Dòng đầu tiên là số tầng của kim tự tháp: 1 <= N <= 10^18
    • Dòng thứ hai là một từ chỉ gồm các kí tự từ A đến Z có độ dài L <= 10^6
    • Dòng thứ ba là số câu hỏi của An: K <= 10^5
    • K dòng tiếp theo gồm tầng số <= N và một kí tự từ A đến Z.
  • Output: stdout
    • Gồm K dòng là một con số là tần suất của kí tự đó tương ứng với input.

Giới hạn:

  • 50 điểm: N <= 1000
  • 70 điểm: L <= 10^5
  • Thời gian tối đa: 1s
  • Bộ nhớ: 32MB ■
2 Likes

Ý anh là tầng K? :thinking:

3 Likes

Không phải, K tầng đó em. Tức là sẽ có K truy vấn đó.

3 Likes

À, vậy thì đoạn sau phải là :point_down: :

Ở K tầng này. :slight_smile:

4 Likes

Nếu từ đưa vào là SHIHAROKU thì tháp sẽ là:

    S
   I H
  H A R
 S U K O
H I H A R

Vậy thì bài làm khá đơn giản.

Với K tầng thì sẽ có 1 + 2 + . . . + K = K * (K + 1) / 2 (ký tự).

Hay đơn giản thì là có K * (K + 1) / 2 div len từ (với len là độ dài của từ) cộng với K * (K + 1) / 2 mod len ký tự đầu của từ.

Để đếm xem trong K tầng đó có bao nhiêu ký tự c thì chỉ cần đếm xem trong từ có bao nhiêu ký tự c đó rồi nhân với số từ trong K tầng.

Lại đếm tiếp trong K * (K + 1) / 2 mod len ký tự đầu của từ rồi cộng với kết quả có được ở trên.

Độ phức tạp là O(L) (L là độ dài từ). :slight_smile:

Code
int shifun(const char *s, const int k, const char c) {
    int len = strlen(s);
    if (!len) return 0;
    int n = k * (k + 1) / 2;
    int quotient = n / len;
    int surplus = n % len;
    int count = 0, sur = 0;

    for (int i = 0; i < len; i++, surplus--)
        if (s[i] == c) {
            count++;
            if (surplus > 0) sur++;
        }
    return count * quotient + sur;
}
Test

https://ideone.com/y48h3Q

P/s: Với điều kiện là tháp như đã nói ở trên, còn không thì là Sai. :smile: Mà nếu vậy thì cho số tầng ban đầu là không cần thiết. :slight_smile: Chắc sai rồi. :blush:

5 Likes

Cái này có một query à bạn :smiley: K query lận.

2 Likes

Anh vô phần test á. :smile:

Còn code em chỉ để thuật toán thôi. :wink:

3 Likes

K*L <= 10^6 * 10^5 = 10^11 :expressionless: chắc 60đ thôi.

5 Likes

Ít vậy :sob: :sob:

Em cũng chỉ mới học, nghĩ sao làm vậy :smile:.

Vậy phải nhờ mọi người chỉ bảo thêm rồi. :blush:

2 Likes

Đi thi kẹt quá thì ăn mấy test nhỏ cũng được :smiley: nhưng thay số vào big-O mà quá giây*10^9 thì ko trọn điểm.

4 Likes

Bài này chắc dùng toán thôi.

Đến tầng k thì có tổng cộng k*(k+1)/2 tất cả -> có floor(L / (k*(k+1)/2)) lần xâu s xuất hiện. Vậy nên là lấy dư của L cho (k*(k+1)/2) rồi đếm thông thường thôi.

Vì xâu không đổi nên lưu lại frequency của từng kí tự A-Z trong xâu s, tính thêm tổng cộng dồn frequency cho từng kí tự, sau đó nhân chia cộng trừ thêm vào.

Độ phức tạp O(L * 26 + N K).

5 Likes

giải thích ko có chữ N nào sao trong đpt lại có N :joy: Chữ K mới đúng chứ

4 Likes

N là số test case mà anh ơi :kissing:

1 Like

N là số tầng mà, chả cần dùng nó trong bài này :V K là số test case

4 Likes

Èo :frowning: :frowning: để em sửa :v

1 Like
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?