noip2016 组合数问题

题目描述

组合数表示的是从n个物品中选出m个物品的方案数。举个例子,从(1,2,3) 三个物品中选择两个物品可以有(1,2),(1,3),(2,3)这三种选择方法。根据组合数的定 义,我们可以给出计算组合数的一般公式:

其中n! = 1 × 2 × · · · × n

小葱想知道如果给定n,m和k,对于所有的0 <= i <= n,0 <= j <= min(i,m)有多少对 (i,j)满足是k的倍数。

输入输出格式

输入格式:

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

接下来t行每行两个整数n,m,其中n,m的意义见【问题描述】。

输出格式:

t行,每行一个整数代表答案。

输入输出样例

输入样例#1:

1 2
3 3

输出样例#1:

1

输入样例#2:

2 5
4 5
6 7

输出样例#2:

0
7

说明

【样例1说明】

在所有可能的情况中,只有是2的倍数。

【子任务】

终于开始填noip的坑了.

分析:其实对于组合数,我们有一个公式:c[i][j] = c[i-1][j-1] + c[i-1][j],但是如果n达到2000,这个数可能会超级大,于是蒟蒻的我在考场上写高精度......其实完全不需要,既然要求mod k = 0的个数,那么我们可以利用公式(a + b) mod c == (a mod c + b mod c) mod c,然后每算出一个c,我们就能根据它是不是0来判断它是不是k的倍数,那么如何求c[0][0]到c[n][m]整除k的个数呢?一般而言,求和要用到前缀和,本题要用到二维前缀和,sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + ok[i][j],优化一下时间,看到t很大,先预处理(2000,2000)的组合数即可.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>

using namespace std;

int t, k, n, m,ans[2010][2010],c[2010][2010],ok[2010][2010];

void init()
{
    c[0][0] = 1;
    for (int i = 1; i <= 2000; i++)
    {
        c[i][0] = 1;
        for (int j = 1; j <= i; j++)
        {
            c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % k;
            if (c[i][j] == 0)
                ok[i][j] = 1;
        }
    }
    for (int i = 1; i <= 2000; i++)
        for (int j = 1; j <= 2000; j++)
            ans[i][j] = ans[i - 1][j] + ans[i][j - 1] - ans[i - 1][j - 1] + ok[i][j];
}

int main()
{
    scanf("%d%d", &t, &k);
    init();
    for (int i = 1; i <= t; i++)
    {
        scanf("%d%d", &n, &m);
        printf("%d\n", ans[n][m]);
    }

    return 0;
}
时间: 2024-10-17 20:36:17

noip2016 组合数问题的相关文章

[NOIP2016]组合数问题 17.5.21 40分

★   输入文件:problem.in   输出文件:problem.out   简单对比 时间限制:1 s   内存限制:512 MB [题目描述] [输入格式] 从文件中读入数据. 第一行有两个整数t, k,其中t代表该测试点总共有多少组测试数据,k的意义见[问题描述]. 接下来t行每行两个整数n, m,其中n, m的意义见[问题描述]. [输出格式] 输出到文件中. t行,每行一个整数代表所有的0<=i<=n,0<=j<=min(i,m)中有多少对(i, j)满足C(j,i)

11-9-2017 星期四 NOIp周

7:42 同余方程 NOIp2012(第一次自己完整推出来); 食物链,又做一遍迷之错误,还有UKE???扒原来的代码???差不多啊???? 10:11 NOIp2016 玩具谜题(模拟...); 准备复习进制转换和高精(只会加减...); 11:31 NOIp2016 组合数问题(杨辉三角+前缀和); 14:27 洛谷P1601 高精度加法; 14:43 洛谷 高精度减法; 准备去爬山了... GG

【NOIP2016】组合数问题

题目描述 Description 输入描述 Input Description 从标准输入读入数据. 第一行有两个整数 t,k,其中 t 代表该测试点总共有多少组测试数据,k 的意义见问题描述. 接下来 t 行每行两个整数 n,m,其中 n,m的意义见问题描述. 输出描述 Output Description 输出到标准输出. tt 行,每行一个整数代表所有的 0≤i≤n,0≤j≤min(i,m) 中有多少对 (i,j)(满足 Cji 是 k 的倍数. 样例输入 Sample Input 1 2

[NOIP2016提高组]组合数问题

题目:UOJ#263.洛谷P2822.Vijos P2006.codevs5947. 题目大意:t组数据,每次给你n和m$\leq 2000$,求对于所有的$(0\leq i\leq n)$,$(0\leq j\leq m)$的(i,j),有多少对满足$C^j_i\equiv 0(mod\ k)$. 解题思路:此题是一道数论题.首先,组合数有一个递推公式:$C^m_n=C^m_{n-1}+C^{m-1}_n$,这其实和杨辉三角的递推公式是一样的.那么我们可以预处理出所有的组合数,然后对于每一个问

UOJ263 【NOIP2016】组合数问题

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转载请注明出处,侵权必究,保留最终解释权! 题目描述 组合数 CmnCnm 表示的是从 nn 个物品中选出 mm 个物品的方案数.举个例子,从 (1,2,3)(1,2,3) 三个物品中选择两个物品可以有 (1,2),(1,3),(2,3)(1,2),(1,3),(2,3) 这三种选择方法.根据组合数的

组合数问题(NOIP2016)

原题传送门 这题啊. 裸的杨辉三角. 预处理杨辉三角和答案即可 下面贴代码 #include<iostream> #include<cstdio> #include<algorithm> using namespace std; int f[2002][2002]; int n,m,q,t; int ans[2002][2002]; int main(){ scanf("%d%d",&t,&q); for(int i=1;i<=

$Noip2016/Luogu2822$ 组合数问题

$Luogu$ 看这题题解的时候看到一个好可爱的表情(●'?'●)?♥ $Sol$ 首先注意到这题的模数是$k$.然而$k$并不一定是质数,所以不能用$C_n^m=\frac{n!}{m!(n-m)!}$. 所以还要记得另外一个公式吖:$C_n^m=C_{n-1}^{m}+C_{n-1}^{m-1}$ 于是可以预处理出所有的$C$,以及所有的前缀和.这样就可以$O(1)$查询了. 最后还要注意特判$m>n$的情况 $over$ $Code$ #include<iostream> #inc

noip2016总结

Day1: T1:模拟: 1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<string> 6 #include<ctime> 7 #include<cmath> 8 #include<set> 9 #include<map> 10 #include<queue&

Lucas定理及组合数取模

引入: 组合数C(m,n)表示在m个不同的元素中取出n个元素(不要求有序),产生的方案数.定义式:C(m,n)=m!/(n!*(m-n)!)(并不会使用LaTex QAQ). 根据题目中对组合数的需要,有不同的计算方法. (1)在模k的意义下求出C(i,j)(1≤j≤i≤n)共n2 (数量级)个组合数: 运用一个数学上的组合恒等式(OI中称之为杨辉三角):C(m,n)=C(m-1,n-1)+C(m-1,n). 证明: 1.直接将组合数化为定义式暴力通分再合并.过程略. 2.运用组合数的含义:设m