中國石油大學ACM俱樂部開放訓練賽---問題 K: 數學問題(預處理 + 二維前綴和)

問題 K: 數學問題

時間限制: 1 Sec  內存限制: 128 MB
提交: 381  解決: 24
[狀態] [提交] [命題人:外部導入]

題目描述

我們高中曾經學過何爲組合數。 那麼,給出整數n,m,g,聰明的你能否求出有多少整數對(i,j),滿足g整除嗎?(其中0≤i≤n,0≤j≤min(i,m))。 (提示:n!=1×2×⋯×n;特別地,0!=1。)

輸入

第一行一個整數T(T<=104 ),表示測試數據的組數;
第二行一個整數g(1<g<=25);
接下來T行每行兩個整數n,m(n,m<=2000);
n,m,g的意義見題目描述。

 

輸出

輸出T行,每行一個整數,表示有多少對整數對(i,j)滿足g整除(0≤i≤n,0≤j≤min(i,m))。

樣例輸入 Copy

1
4
5 4

樣例輸出 Copy

2

利用二維前綴和 s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1],將(n,m)範圍內整數對對數預先打表出來,把每次查詢優化到 O(1)。

坑點:n 有可能 < m

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int N = 2e3 + 10;

ll a[N][N];
ll sum[N][N];
ll g;

void init()
{
    memset(a, 0, sizeof(a));
    a[0][0] = 1;
    for(int i = 1; i < N; ++i)
    {
        a[i][0] = 1;
        a[i][i] = 1;
        for(int j = 1; j < i; ++j)
        {
            a[i][j] = ((a[i - 1][j] % g) + (a[i - 1][j - 1] % g)) % g;
        }
    }
}

void solve()
{
    memset(sum, 0, sizeof(sum));
    for(int i = 1; i < N; ++i)
    {
        for(int j = 1; j <= i; ++j)
        {
            sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
            if(a[i][j] == 0)
            {
                sum[i][j]++;
            }
        }
        sum[i][i + 1] = sum[i][i];
    }
}

int main()
{
    int n, t, m;
    while(~scanf("%d", &t))
    {
        scanf("%lld", &g);
        init();
        solve();
        while(t--)
        {
            scanf("%d%d", &n, &m);
            if(n < m)
                m = n;
            cout<<sum[n][m]<<'\n';
        }
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章