Luogu P2822 组合数问题(前缀和)

P2822 组合数问题

题意

题目描述

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

\[C_n^m=\frac{n!}{m!(n-m)!}\]

其中\(n!=1\times 2\times \cdots \times n\);特别地,定义\(0!=1\)。

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

输入输出格式

输入格式:

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

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

输出格式:

共\(t\)行,每行一个整数代表所有的\(0\leq i\leq n,0\leq j\leq \min \left( i,m\right)\)中有多少对\((i,j)\)满足\(C_i^j\)是\(k\)的倍数。

输入输出样例

输入样例#1:

1 2
3 3

输出样例#1:

1

输入样例#2:

2 5
4 5
6 7

输出样例#2:

0
7

说明

【样例1说明】

在所有可能的情况中,只有\(C_2^1=2\)是\(2\)的倍数。

【子任务】

思路

\(10\)个月以前,当我和一位数竞党聊起这道题的时候,他启发我,可以利用\(k\)的特性来特判每一个数据点。当时的我嫌麻烦,没有这样写。如今问了\(Mercury\)这道题的做法,才发现正解才是\(OI\)思维,之前的想法太偏数学了。

首先,杨辉三角的值与组合数相同,我们可以用求杨辉三角的方法很快求出组合数。在求的过程中,组合数对\(k\)取模,若该位为\(0\),则说明它是\(k\)的倍数。

然后就是这道题的精髓了:用一个二维数组\(s[i][j]\)统计组合数为\(0\)的情况的前缀和。转移方法是:\(s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+[c[i][j]=0]\)。

然后直接输出前缀和就好啦。

AC代码

#include<bits/stdc++.h>
using namespace std;
int t,k,a[2005][2005],s[2005][2005];
int read()
{
    int re=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
    return re;
}
int main()
{
    t=read(),k=read();
    a[1][1]=1;
    for(int i=2;i<=2001;i++)
    {
        for(int j=1;j<=i;j++) a[i][j]=(a[i-1][j-1]+a[i-1][j])%k;
        for(int j=1;j<=i;j++) s[i][j]=s[i][j-1]+(!a[i][j]);
        for(int j=i+1;j<=2001;j++) s[i][j]=s[i][i];
        for(int j=1;j<=2001;j++) s[i][j]+=s[i-1][j];
    }
    while(t--)
    {
        int x=read(),y=read();
        printf("%d\n",s[x+1][y+1]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/coder-Uranus/p/9902716.html

时间: 2024-08-30 14:06:47

Luogu P2822 组合数问题(前缀和)的相关文章

做题记录:P2822 组合数问题

P2822 组合数问题 /*思路:组合数就是杨辉三角,那么我们只要构造一个杨辉三角就行了. 记得要取模,不然会爆.然后,再用二维前缀和统计各种情况下组合数是k的 倍数的方案数.询问时直接O(1)输出即可.*/ #include<iostream> #include<cstdio> #include<fstream> #include<algorithm> #include<string> #include<sstream> #incl

P2822 组合数问题

P2822 组合数问题 标签:NOIp提高组 2016 云端↑ 难度: 普及+/提高 时空限制: 1s / 512MB 题目描述 组合数表示的是从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,

Luogu P1470 最长前缀 Longest Prefix

Luogu P1470 最长前缀 Longest Prefix Portal(传送门) 注释 这道题与上一篇博客的题几乎一样 解析 有点麻烦的地方就是字符串的输入 方法一:类dp Code #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define LL long long using namespace std

洛谷——P2822 组合数问题

https://www.luogu.org/problem/show?pid=2822 题目描述 组合数C_n^mC?n?m??表示的是从n个物品中选出m个物品的方案数.举个例子,从(1,2,3) 三个物品中选择两个物品可以有(1,2),(1,3),(2,3)这三种选择方法.根据组合数的定 义,我们可以给出计算组合数的一般公式: C_n^m=\frac{n!}{m!(n - m)!}C?n?m??=?m!(n−m)!??n!?? 其中n! = 1 × 2 × · · · × n 小葱想知道如果给

组合数问题

组合数公式: 计算组合数的递推方法: C[i, j] := C[i - 1, j] + C[i - 1, j - 1]  (0 < i ≤ j ≤ m ≤ n) 与杨辉三角在形式上一致. 代码: for (int i = 1; i <= n; i++) { c[i][1] = i % k; c[i][i] = 1; // 预处理 } for (int i = 2; i <= n; i++) for (int j = 2; j <= i - 1; j++) // 递推 c[i][j]

LuoguP2822 组合数问题(组合数,二维前缀和)

P2822 组合数问题 输入输出样例 输入样例#1: 复制 1 2 3 3 输出样例#1: 复制 1 输入样例#2: 复制 2 5 4 5 6 7 输出样例#2: 复制 0 7 说明 [样例1说明] 在所有可能的情况中,只有C_2^1 = 2C21?=2是2的倍数. [子任务] #include<bits/stdc++.h> #define N 2001 #define ll long long using namespace std; ll n,m,t,k,ans,cnt; ll C[N+5

HDU4779 Tower Defense 组合数学

原文链接https://www.cnblogs.com/zhouzhendong/p/HDU4779.html 题目传送门 - HDU4779 题意 $T$ 组数据. 给定一个 $n\times m$ 的棋盘,要在上面放最多 $P$ 个重塔和最多 $Q$ 个轻塔. 每一个塔都会攻击同行和同列的塔.轻塔不能承受任何攻击.重塔最多可以承受一个塔的攻击. 所有重塔全是一样的,所有轻塔也是一样的,但是重塔和轻塔不同. 现在问你有多少放置塔(至少放一个塔)的方案.答案对于 $1e9+7$ 取模. $1\l

【AtCoder】CODE FESTIVAL 2017 qual B

最近不知道为啥被安利了饥荒,但是不能再玩物丧志了,不能颓了 饥荒真好玩 A - XXFESTIVAL CCFESTIVAL #include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define mp make_pair #define pb push_back #define space putchar(' ') #define enter putchar('\n'

AC日记——组合数问题 落谷 P2822 noip2016day2T1

题目描述 组合数表示的是从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代表该测试点总共有多少