洛谷题单指南-数学基础问题-P2822 [NOIP2016 提高组] 组合数问题

原题链接:https://www.luogu.com.cn/problem/P2822

题意解读:本质上是要计算所有组合数C(i,j),

解题思路:

本题要解决两个问题:

1、 计算C(0~n、0~m)范围内所有的组合数,只用保留%k的结果

2、统计有多少个C(i,j)等于0,

#include <bits/stdc++.h>
using namespace std;

const int N = 2005;

int c[N][N];

int t, k, n, m;

int main()
{
    cin >> t >> k;
    //预计算所有组合数 % k
    for(int i = 0; i <= 2000; i++)
    {
        for(int j = 0; j <= i; j++)
        {
            if(j == 0) c[i][j] = 1 % k;
            else c[i][j] = (c[i - 1][j] % k + c[i - 1][j - 1] % k) % k;
        }
    }
    
    while(t--)
    {
        cin >> n >> m;
        int cnt = 0;
        for(int i = 0; i <= n; i++)
        {
            int e = min(i, m);
            for(int j = 0; j <= e; j++)
            {
                if(c[i][j] == 0)
                {
                    cnt++;
                } 
            }
        }
        cout << cnt << endl;
    }
    return 0;
}

C(0,0)    
C(1,0) C(1,1)  
C(2,0) C(2,1) C(2,2)
C(3,0) C(3,1) C(3,2)

要枚举并计数

即要统计(0,0)到(3,2)区间范围有多少个0,可以采用二维前缀和预计算,复杂度为O(1),注意排除掉j>i的数据影响。

二维前缀和:

已知数组a[i][j],前缀和数组s[i][j],s[i][j]表示a数组 1-i行、1-j列所有元素的和

递推公式:s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + a[i][[j]

作用:求区间和

(x1,y1)(x2,y2)之间所有元素的和为s[x2][y2] - s[x2][y1-1] - s[x1-1][y2] + s[x1-1][y1-1]

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 2005;

int c[N][N];
int s[N][N]; //前缀和数组

int t, k, n, m;

int main()
{
    cin >> t >> k;
    //预计算所有组合数 % k
    for(int i = 0; i <= 2000; i++)
    {
        for(int j = 0; j <= i; j++)
        {
            if(j == 0) c[i][j] = 1 % k;
            else c[i][j] = (c[i - 1][j] % k + c[i - 1][j - 1] % k) % k;
        }
    }

    //预计算前缀和,前缀和数组下标从1开始,对应c数组下标要减1
    for(int i = 1; i <= 2001; i++)
    {
        for(int j = 1; j <= 2001; j++)
        {
            int a = 0;
            if(j - 1 <= i - 1 && c[i - 1][j - 1] == 0) a = 1;
            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a;
        }
    }

    
    while(t--)
    {
        cin >> n >> m;
        cout << s[n + 1][min(n + 1, m + 1)] << endl;
    }
    return 0;
}

 

posted @ 2024-04-08 15:18  五月江城  阅读(34)  评论(0编辑  收藏  举报