组合数学+ybt题解
加法原理
乘法原理
排列数
从
全排列
组合数
从
如何理解呢?就是把取出来的排列方案数取缔为一个组合,对于取出来的排列的方案数有
特别的,规定
二项式定理
通过这个式子,我们可以求出展开式的系数,另外的,杨辉三角也遵循这个规律
证明
二项式定理表明,对于任何正整数
其中,
下面使用数学归纳法来证明二项式定理:
基础步骤(n=0):
当
归纳假设:
假设当
归纳步骤:
我们需要证明当
考虑
展开右边的乘积,我们得到:
将两个求和式合并,我们可以重新排列和组合项:
注意到第二个求和式中的项可以重新索引,将
将两个求和式合并,并注意到当
利用组合数的性质
这正是我们要证明的
由基础步骤和归纳步骤,我们可以得出结论,二项式定理对所有正整数
组合数的递推
为什么这个公式成立呢? 考虑一种dp思想,如果我选第n个数,那么我有
贴图真好用(逃
组合数的性质
考虑一个n位的二进制数,能组成的数有
卢卡斯定理及证明
ps:一般
T1:
递推出阶乘,再用快速幂算乘法逆元和次方即可
T2:
卢卡斯定理板子题
我们现预处理出模数以内的阶乘,然后用卢卡斯定理递归到模数以内后求解
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e4,p=10007;
int t,n,m;
int fac[N],lg[60];
int quickpow(int x,int k){
lg[0]=x;
for(int i=1;i<=30;i++){
lg[i]=lg[i-1]*lg[i-1]%p;
}
int res=1;
for(int i=0;i<=30;i++){
if(!((k>>i)&1)) continue;
res=res*lg[i]%p;
}
return res;
}
int C(int n,int m){
if(n<m) return 0;
if(m==0) return 1;
return fac[n]*quickpow(fac[m],p-2)%p*quickpow(fac[n-m],p-2)%p;
}
int lucas(int n,int m){
if(n<m) return 0;
if(m==0) return 1;
return C(n%p,m%p)*lucas(n/p,m/p)%p;
}
signed main(){
fac[0]=1;
for(int i=1;i<=p;i++){
fac[i]=fac[i-1]*i%p;
}
scanf("%lld",&t);
while(t--){
scanf("%lld%lld",&n,&m);
printf("%lld\n",lucas(n,m));
}
return 0;
}
T3:
数论大杂烩!
还是很好理解的题解
代码:
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e4,mod=999911659;
int n,g;
int sum[5],lg[60],fac[5][N];
int p[6]={0,2,3,4679,35617,999911659};
int quickpow(int x,int k,int md){
lg[0]=x;
for(int i=1;i<=40;i++){
lg[i]=lg[i-1]*lg[i-1]%p[md];
}
int res=1;
for(int i=0;i<=40;i++){
if(!((k>>i)&1ll)) continue;
res=res*lg[i]%p[md];
}
return res;
}
int fan(int x,int y,int md){
return quickpow(x,y-2,md);
}
int C(int n,int m,int md){
if(n<m) return 0;
if(m==0) return 1;
return fac[md][n]*fan(fac[md][m],p[md],md)%p[md]*fan(fac[md][n-m],p[md],md)%p[md];
}
int lucas(int n,int m,int md){
if(n<m) return 0;
if(m==0) return 1;
return C(n%p[md],m%p[md],md)*lucas(n/p[md],m/p[md],md)%p[md];
}
signed main(){
for(int j=1;j<=4;j++){
fac[j][0]=1;
for(int i=1;i<=p[j];i++){
fac[j][i]=fac[j][i-1]*i%p[j];
}
}
scanf("%lld%lld",&n,&g);
if(g%mod==0){
printf("0\n");
return 0;
}
for(int i=1;i*i<=n;i++){
if(n%i!=0) continue;
for(int j=1;j<=4;j++){
sum[j]+=lucas(n,i,j);
}
if(i*i==n) continue;
for(int j=1;j<=4;j++){
sum[j]+=lucas(n,n/i,j);
}
}
int ans=0;
for(int i=1;i<=4;i++){
int k=(mod-1)/p[i];
int c=quickpow(k,p[i]-2,i);
ans+=sum[i]*k*c;
ans%=mod-1;
}
printf("%lld",quickpow(g,ans,5));
}
T4:
实际意义:有n个带编号的球,划分成标号连续的k段
然后考虑隔板法,答案就是
然后这题需要用到高精,懒得写了
T5:
把这个图形恒着切成两个矩形,然后枚举多少辆车在第一个矩形中,然后统计答案数即可
T6:
首先我们先把相同的数看成连续的一块
然后利用隔板问题,枚举可以分成
然后考虑在块里填数,方案数即为
特殊情况:
ps:预处理逆元可以将复杂度降到
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5,mod=2e6+3;
int n,ans;
int fac[N],inv[N],lg[50];
int quickpow(int x,int k){
lg[0]=x;
for(int i=1;i<=30;i++){
lg[i]=lg[i-1]*lg[i-1]%mod;
}
int res=1;
for(int i=0;i<=30;i++){
if(!((k>>i)&1ll)) continue;
res=lg[i]*res%mod;
}
return res;
}
int C(int b,int a){
return fac[a]*inv[b]%mod*inv[a-b]%mod;
}
signed main(){
scanf("%lld\n",&n);
fac[0]=1;
for(int i=1;i<=n;i++){
fac[i]=fac[i-1]*i%mod;
}
inv[n]=quickpow(fac[n],mod-2);
for(int i=n-1;i>=0;i--){
inv[i]=inv[i+1]*(i+1)%mod;
}
ans=n;
for(int i=2;i<=n;i++){
ans+=2*C(i,n)%mod*C(i-1,n-1)%mod;
ans%=mod;
}
printf("%lld\n",ans);
return 0;
}
T3:
chat_GLM真好用(逃
然后
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探