简单组合计数
简单组合计数
组合计数基础
几个原理:
1.加法原理:若完成一件事有
2.乘法原理:若完成一件事有
几个定义:
1.排列数:从
注意是
2.组合数:从
性质:
1.
2.
3.
4.
5.
6.
7.Lucas定理:若
这个注意代码实现的时候得递归实现
二项式定理
多项式定理
设
这里把
多重集的排列数
多重集是允许包含重复元素的集合,设集合
多重集的组合数
设集合
则从该集合中选出
Catlan数
定义
与其有关的问题:
1.给定n个左括号和n个右括号组成合法的括号序列的个数为
2.
3.n个节点组成的不同二叉树的数量是
4.在平面直角坐标系中每一步只能向上或者向右走,从点
几个结论:
1.将一个长度为n的环变作n个自环至少要将节点交换n-1次
2.设
3.遇到序列上的错位,需要交换位置还原的问题可以往图论方向想
exlucas
用途:快速求出以下式子的值(p不一定是质数)
遇到这种情况,我们可以将p进行算术基本定理的质因数分解。设
这样我们就把问题简化成了:
这个一次同余式组直接用中国剩余定理
问题在于如何求出
先来看简化版扩展卢卡斯:
题意:给定整数
因为999911659是一个质数,由扩欧得:
原式等价于
所以本题关键在于计算
按照扩展卢卡斯的思路,我们将999911658分解质因数发现:
我们枚举n的约数d,分成四个,运用Lucas定理分别计算组合数
当然对于质数的逆元啥的自己预处理一下就可以
现在我们的问题就是求解同余方程组
然后用快速幂进行计算即可
#define int long long
int mod=999911659,p[4]={2,3,4679,35617},n,m,cnt,ans,q;
int ys[40000],jc[40000],a[4],x,y,t;
int power(int a,int b,int p){
int ans=1;
while(b){
if(b&1)ans=ans*a%p;
a=a*a%p;
b>>=1;
}
return ans;
}
int C(int n,int m,int p){
return n<m?0:jc[n]*power(jc[m]*jc[n-m],p-2,p)%p;
}
int lucas(int n,int m,int p){
return m?C(n%p,m%p,p)*lucas(n/p,m/p,p)%p:1;
}
int exgcd(int a,int b,int &x,int &y){
if(!b){
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,x,y);
int t=x;
x=y,y=t-(a/b)*y;
return d;
}
signed main(){
scanf("%lld%lld",&n,&q);
if(q%mod==0){
puts("0");
return 0;
}
jc[0]=1;
m=sqrt(n);
for(int i=1;i<=m;i++){
if(n%i==0){
ys[++cnt]=i,ys[++cnt]=n/i;
}
}
cnt-=ys[cnt-1]==ys[cnt];
for(int i=0;i<4;i++){
for(int j=1;j<p[i];j++){
jc[j]=jc[j-1]*j%p[i];
}
for(int j=1;j<=cnt;j++){
a[i]=(a[i]+lucas(n,ys[j],p[i]))%p[i];
}
exgcd((mod-1)/p[i],p[i],x,y);
ans=(ans+a[i]*(x%p[i]+p[i])*(mod-1)/p[i])%(mod-1);
}
printf("%lld\n",power(q,ans,mod));
return 0;
}
这也就是所有的
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!