+8

View Animation Rotation trong Swift

Ý tưởng

Nhận xét thấy, một đường đi thỏa mãn gồm m+nm + n bước đi (mỗi bước đi là một cạnh ô vuông). Tại mỗi bước đi chỉ được chọn một trong hai giá trị đi lên (ta đặt là 11) hoặc đi sang phải (ta đặt là 00). Số bước đi lên đúng bằng nn và số bước sang phải đúng bằng mm. Bài toán lúc này dẫn đến việc tìm xem có bao nhiêu dãy nhị phân có độ dài m+nm + n trong đó có đúng nn thành phần có giá trị bằng 11. Dựa trên bài toán chia kẹo Euler, kết quả cần tìm lúc này là (m+nm)m + n \choose m. Ta có thể tính tổ hợp (nk)n \choose k bằng quy hoạch động dựa trên tính chất sau của tổ hợp:

(nk)=(n1k1)+(n1k){n \choose k} = {n - 1 \choose k - 1} + {n - 1 \choose k}

Độ phức tạp: O(n2)O(n^2). Các bạn cần kết hợp với việc tính toán modulo liên tục để tránh gây ra tràn số nếu như sử dụng ngôn ngữ C++.

Cài đặt

#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
long long ncr[5005][5005], n, m;
void pre_compute()
{
    int k;
    for (int i = 0; i < 5001; i++)
    {
        ncr[i][0] = ncr[i][i] = 1;
        // Chỉ tính đến vị trí cột thứ i / 2 là đủ cho hàng i.
        k = i >> 1;
        for (int j = 1; j < k + 1; j++)
            ncr[i][j] = ncr[i][i - j] = (ncr[i - 1][j] + ncr[i - 1][j - 1]) % MOD;
    }
}
int main()
{
    int m, n;
    cin >> m >> n;
    pre_compute();
    cout << ncr[m + n][m];
    return 0;
}

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí