zoukankan      html  css  js  c++  java
  • 题解 【NOIP2016】组合数问题

    【NOIP2016】组合数问题

    Description

    Pic

    Input

    第一行有两个整数t, k,其中t代表该测试点总共有多少组测试数据,k的意义见【问题描述】。
    接下来t行每行两个整数n, m,其中n, m的意义见【问题描述】。

    Output

    t行,每行一个整数代表所有的0<=i<=n,0<=j<=min(i,m)中有多少对(i, j)满足C(j,i)是k的倍数。

    Sample Input

    输入1:
    1 2
    3 3

    输入2:
    2 5
    4 5
    6 7

    Sample Output

    输出1:
    1

    输出2:
    0
    7

    Hint

    样例1提示:
    在所有可能的情况中,只有C(1,2)是2的倍数。

    输出范围:
    Pic

    Source

    NOIP2016 ,数学, 杨辉三角

    解析

    这题看上去确实很难做哈。

    毕竟这数据范围。。

    但实际上,我们完全可以利用杨辉三角预处理出组合数模k的值,

    这样只要模k为0就是k的倍数了。

    然后再O(2000*2000)记录下次数就能O(1)回答了。

    上AC代码:

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    int t,k,m,n;
    int f[2002][2002],a[2002][2002];
    
    int main(){
        scanf("%d%d",&t,&k);
        for(int i=0;i<=2000;i++){
            f[i][0]=1%k;
        }
        for(int i=1;i<=2000;i++){
            for(int j=1;j<=i;j++){
                f[i][j]=(ll)(f[i-1][j]+f[i-1][j-1])%k;
            }
        }/*计算杨辉三角模k的值*/
        if(!f[0][0]) a[0][0]=1;
        for(int i=1;i<=2000;i++){
            a[i][0]=a[i-1][0]+(f[i][0]==0);
            for(int j=0;j<i;j++){
                a[i][j]=a[i-1][j]+a[i][j-1]-a[i-1][j-1]+(f[i][j]==0);
                //如果值为0就是k的倍数
            }
            a[i][i]=a[i][i-1]+(f[i][i]==0);
            for(int j=i+1;j<=2000;j++) a[i][j]=a[i][i];
        }/*预处理计数*/
        for(int i=1;i<=t;i++){
            scanf("%d%d",&n,&m);
            printf("%d
    ",a[n][m]);
            //O(1)回答
        }
        return 0;
    }
  • 相关阅读:
    CF 461B Appleman and Tree
    POJ 1821 Fence
    NOIP 2012 开车旅行
    CF 494B Obsessive String
    BZOJ2337 XOR和路径
    CF 24D Broken robot
    POJ 1952 BUY LOW, BUY LOWER
    SPOJ NAPTIME Naptime
    POJ 3585
    CF 453B Little Pony and Harmony Chest
  • 原文地址:https://www.cnblogs.com/zsq259/p/10458722.html
Copyright © 2011-2022 走看看