CF630G 题解
WYZ20030051 · · 题解
前言
这道题算是一道入门的组合数学题,难度不大,适合刚学组合数学的同学写。其实主要的几种思路其他题解已经说的比较清楚了,这篇题解除了会对题目进行讲解以外还会再补充一些其他与组合数学入门的内容。
正文
这道题的题意很简单:给定 5 面红旗, 3 面蓝旗以及
这道题读完之后很容易想到用组合数来解决该题,那么具体应该如何解决呢?
分析题意可提取如下几个关键点:
- “当所有的旗分配完后,在某一张桌子上红旗,蓝旗,红旗与红旗,红旗,蓝旗这样类似的不记为不同种”,也就是旗的顺序对这道题并没有影响。
- 一张桌子上可以放红旗和多张蓝旗。
- 题中的红旗与蓝旗是互不干扰的。
第一点和第二点暗示了这道题其实就是可重复组合,所以可以使用公
对于红旗,桌子有
则最终答案为
那么现在我们已经知道答案是什么了,接下来要做的就是如何得到答案。
我们现在要做的只有求出组合数
- 暴力模拟出
C 的公式,以得到答案。 - 预处理出求出
C 需要的相关内容后再求出C 。 - 用递推的方式求出
C 。 - 用卢卡斯定理求出
C (这种方法适用于n 、m 比较大,但模数较小的情况)。
由于本题 n 的范围较小,所以可以三种方法都可以通过本题,其中第二种是最常用的。由于并没有人用递推的方式求出
组合数的递推式是
CODE
#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<cassert>
#include<stack>
#include<queue>
#include<vector>
#include<map>
#include<cstdlib>
using namespace std;
#define ll long long
#define ull unsigned long long
#define int ll
int read()
{
int now=0,nev=1;
char c=getchar();
while(c<'0' || c>'9')
{
if(c=='-')
nev=-1;
c=getchar();
}
while(c>='0' && c<='9')
{
now=(now<<1)+(now<<3)+(c&15);
c=getchar();
}
return now*nev;
}
const int MAXN=510;
int n;
int C[MAXN][MAXN];
void get_C()
{
for(int i=0;i<=n+4;i++)//最多用到 n+4,且这题是单次询问,所以 i 只要循环到 n+4 就够了
{
for(int j=0;j<=i && j<=5;j++)//最多用到 5,所以这题 j 只要循环到 5 就够了
{
if(j==0)
C[i][j]=1;
else
C[i][j]=C[i-1][j]+C[i-1][j-1];
}
}
}
signed main()
{
n=read();
get_C();
printf("%lld",C[n+4][5]*C[n+2][3]);
return 0;
}
结尾
此题很适合刚学组合数的同学入门(为什么我到现在了才知道这道题....),希望这篇题解能对大家有帮助。