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) 这三种选择方法。根据组合数的定义,我们可以给出计算组合数 CmnCnm 的一般公式:

Cmn=n!m!(n?m)!Cnm=n!m!(n?m)!

其中 n!=1×2×?×nn!=1×2×?×n;特别地,定义 0!=10!=1。

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

输入格式

从标准输入读入数据。

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

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

输出格式

输出到标准输出。

tt 行,每行一个整数代表所有的 0≤i≤n,0≤j≤min(i,m)0≤i≤n,0≤j≤min(i,m) 中有多少对 (i,j)(i,j) 满足 CjiCij 是 kk 的倍数。

样例一

input

1 2
3 3

output

1

explanation

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

样例二

input

2 5
4 5
6 7

output

0
7

正解:矩阵前缀和+组合数学解题报告:  

  这是一道很简单的数学题,可以发现其实如果根据组合中的一个基本公式:C(n,m)=C(n-1,m)+C(n-1,m-1),就可以直接递推出2000以内的所有的组合数。而我们只需要判断有多少个点对满足是k的倍数,很容易想到只要对k取模,对于为0的C(i,j)是肯定满足是k的倍数的。

  因为k是所有询问共用的,可以一开始就预处理出矩阵前缀和,之后每次O(1)查询就可以了。


注意事项:

  很多人在考场上写的是质因数分解,但是很明显有一些k并不是质数,所以并不能直接分解,应该先对k进行质因数分解,在对于这些质因数在递推中分析。

    
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <algorithm>
 6 #include <string>
 7 #include <ctime>
 8 #include <queue>
 9 #include <vector>
10 #include <cstdlib>
11 using namespace std;
12 typedef long long LL;
13 const int MAXN = 2011;
14 int T,k,n,m,ans;
15 int C[MAXN][MAXN],a[MAXN][MAXN];
16 int sum[MAXN][MAXN];
17
18 void work(){
19     scanf("%d%d",&T,&k);
20     C[1][0]=C[1][1]=1;
21     for(int i=2;i<=2000;i++){
22         C[i][0]=1;
23         for(int j=1;j<=i;j++) {
24             C[i][j]=C[i-1][j-1]+C[i-1][j];
25             C[i][j]%=k;
26             if(C[i][j]==0) {
27                 a[i][j]=1;
28             }
29         }
30     }
31     for(int i=1;i<=2000;i++)
32         for(int j=1;j<=2000;j++)
33             sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
34
35     while(T--) {
36         scanf("%d%d",&n,&m); m=min(m,n);
37         printf("%d\n",sum[n][m]);
38     }
39 }
40
41 int main()
42 {
43     work();
44     return 0;
45 }
时间: 2024-08-23 19:58:42

UOJ263 【NOIP2016】组合数问题的相关文章

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代表该测试点总共有多少

[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$,这其实和杨辉三角的递推公式是一样的.那么我们可以预处理出所有的组合数,然后对于每一个问

组合数问题(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