组合数取模(lucas定理+CRT合并)(AC)
#include<bits/stdc++.h>
#define re register
#define int long long
using namespace std;
int T,n,m,mod,ans=;
inline int read(){
re int a=,b=;re char ch=getchar();
while(ch<''||ch>'')
b=(ch=='-')?-:,ch=getchar();
while(ch>=''&&ch<='')
a=(a<<)+(a<<)+(ch^),ch=getchar();
return a*b;
}
inline int qpow(re int a,re int b,re int p){
re int res=;a%=p;
for(;b;b>>=){
if(b&)res=res*a%p;
a=a*a%p;
}
return res%p;
}
inline int exgcd(re int a,re int b,re int &x,re int &y){
re int d=a;
if(!b){x=,y=;return a;}
d=exgcd(b,a%b,y,x);
y-=(a/b)*x;
return d;
}
inline int inv(re int a,re int m){
re int x,y;
re int d=exgcd(a,m,x,y);
return d==?(m+x%m)%m:-;
}
inline int mul(re int n,re int pi,re int pk){
if(!n)return ;
re int ans=;
if(n/pk){
for(re int i=;i<=pk;i++)
if(i%pi) ans=ans*i%pk;
ans=qpow(ans,n/pk,pk);
}
for(re int i=;i<=n%pk;i++)
if(i%pi) ans=ans*i%pk;
return ans*mul(n/pi,pi,pk)%pk;
}
inline int C(re int n,re int m,re int p,re int pi,re int pk)
{
if(m>n)return ;
re int a=mul(n,pi,pk),b=mul(m,pi,pk),c=mul(n-m,pi,pk);
re int k=,ans;
for(re int i=n;i;i/=pi) k+=i/pi;
for(re int i=m;i;i/=pi) k-=i/pi;
for(re int i=n-m;i;i/=pi) k-=i/pi;
ans=a*inv(b,pk)%pk*inv(c,pk)%pk*qpow(pi,k,pk)%pk;
ans=ans*(p/pk)%p*inv(p/pk,pk)%p;
return ans;
}
inline int lucas(re int m,re int n,re int p){
re int x=p,ans=;
for(re int i=;i<=p;i++){
if(!(x%i)){
re int pk=;
while(!(x%i))pk*=i,x/=i;
ans=(ans+C(n,m,p,i,pk))%p;
}
}
return ans;
}
signed main(){
T=read(),mod=read();
n=read(),m=read();
if(mod==||T<n+m){puts("");return ;}
for(re int k=m;k<=(T+m-n)/;k++)
ans+=lucas(k,T,mod)%mod*lucas(k-m,T-k,mod)%mod*lucas((T+m+n-(k<<))/,T-(k<<)+m,mod)%mod;
printf("%lld\n",ans%mod);
return ;
}
#include<bits/stdc++.h>
#define re register
#define ll long long
using namespace std;
ll T,n,m,mod,ans=;
inline ll read(){
re ll a=,b=;re char ch=getchar();
while(ch<''||ch>'')
b=(ch=='-')?-:,ch=getchar();
while(ch>=''&&ch<='')
a=(a<<)+(a<<)+(ch^),ch=getchar();
return a*b;
}
inline void exgcd(re ll &x,re ll &y,re ll a,re ll b)
{
if(!b){x=,y=;return;}
exgcd(x,y,b,a%b);
ll tmp=x;x=y;
y=tmp-a/b*y;
}
inline ll inv(re ll a,re ll p)
{
re ll x,y;
exgcd(x,y,a,p);
return x;
}
inline ll qpow(re ll a,re ll b,re ll p){
re ll res=;a%=p;
for(;b;b>>=){
if(b&)res=res*a%p;
a=a*a%p;
}
return res%p;
}
inline ll fac(re ll n,re ll p,re ll tp)
{
if(!n) return ;
re ll f=,res=;
for(re ll i=;i<tp;i++)
{
if(i%p) (f*=i)%=tp;
if(i==n%tp) res=f;
}
f=qpow(f,n/tp,tp);
return fac(n/p,p,tp)*f%tp*res%tp;
}
inline ll C(re ll m,re ll n,re ll p,re ll tp)
{
re ll ct=;
for(re ll i=m;i;i/=p) ct+=i/p;
for(re ll i=n;i;i/=p) ct-=i/p;
for(re ll i=m-n;i;i/=p) ct-=i/p;
return fac(m,p,tp)*inv(fac(n,p,tp),tp)%tp*inv(fac(m-n,p,tp),tp)%tp*qpow(p,ct,tp)%tp;
}
inline ll CRT(re ll m,re ll n,re ll p,re ll tp)
{
return C(m,n,p,tp)*(mod/tp)%mod*inv(mod/tp,tp)%mod;
}
inline ll lucas(re ll n,re ll m,re ll p)
{
ll ans=;
for(re ll i=;i*i<=p;i++)
{
if(p%i==)
{
re ll tp=;
while(p%i==) tp*=i,p/=i;
(ans+=CRT(m,n,i,tp))%=mod;
}
}
if(p!=) (ans+=CRT(m,n,p,p))%=mod;
return (ans%mod+mod)%mod;
}
signed main(){
T=read(),mod=read();
n=read(),m=read();
if(mod==||T<n+m){puts("");return ;}
for(re int k=m;k<=(T+m-n)/;k++)
ans+=lucas(k,T,mod)%mod*lucas(k-m,T-k,mod)%mod*lucas((T+m+n-(k<<))/,T-(k<<)+m,mod)%mod;
printf("%lld\n",ans%mod);
return ;
}
以下是ac代码
附上新的公式推导方式(经实测可AC)
设k为向上走的步数(纯的,不包括向下),那么向下走的步数为k-m
即C(T,k)×C(T-k,k-m);
由上式可推出 向右的与向左的步数之和为T-2*k+m,而向右的比向左的多n,利用和差公式,易得,向右的为(T-2*k+m+n)/2;
且k>=m,(T-2*k+m+n)/2>=n;可得,k->[m,(T+m-n)/2];
故整体公式为
∑(k->[m,(T+m-n)/2])(C(T,k)×C(T-k,k-m)×C(T-2*k+m,(T-2*k+m+n)/2));
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define QAQ 100010
#define re register
#define int long long
#define ll long long
#define fup(i,a,b) for(re int i=a;i<=b;++i)
#define fdn(i,a,b) for(re int i=a;i>=b;--i)
int n,m,mod,t;
ll ans;
int fac[QAQ],inv[QAQ];
int tot,p[QAQ],w[QAQ];
inline int quick_fk_me(re int a,re int b,re int pk){
int ans=;
for(;b;b>>=){
if(b&)ans=1ll*ans*a%pk;
a=1ll*a*a%pk;
}
}
void exgcd(re ll a,re ll b,re ll &x,re ll &y){
if(b==){x=,y=;return;}
exgcd(b,a%b,x,y);
re int z=x;
x=y,y=z-a/b*y;
}
inline ll crt(){
re ll ans=,lcm=,x,y;
fup(i,,tot)lcm*=p[i];
fup(i,,tot){
re ll tmp=lcm/p[i];
exgcd(tmp,p[i],x,y);
x=(x%p[i]+p[i])%p[i];
ans=(ans+tmp*x*w[i])%lcm;
}
return (ans+lcm)%lcm;
}
inline void Get_fac_and_inv(re int top,re int pk){
fac[]=fac[]=inv[]=inv[]=;
fup(i,,top)fac[i]=1ll*fac[i-]*i%pk;
fup(i,,top)inv[i]=(pk-pk/i)*inv[pk%i]%pk;
fup(i,,top)inv[i]=1ll*inv[i-]*inv[i]%pk;
}
int CC(re int n,re int m,re int pk){
if(m>n)return ;
return fac[n]*inv[m]%pk*inv[n-m]%pk;
}
int lucas(re int n,re int m,re int pk){
if(!m)return ;
return CC(n%pk,m%pk,pk)*lucas(n/pk,m/pk,pk)%pk;
}
inline bool divide(int n){
re int top=sqrt(n);
fup(i,,top){
if(n%i)continue;
p[++tot]=i;
while(n%i==)n/=i;
}
if(n>)p[++tot]=n;
return tot==;
}
main(){
scanf("%lld%lld",&t,&mod);
scanf("%lld%lld",&n,&m);
if(n<)n=-n;
if(m<)m=-m;
re int st=m,ed=(t+m-n)>>;
if(divide(mod)){
Get_fac_and_inv(min(t,mod),mod);//什么纱吊错 妈耶 不求阶乘??!!
fup(k,st,ed)
ans=(ans+lucas(t,k,mod)*lucas(t-k,k-m,mod)%mod*lucas(t-*k+m,(t-*k+m-n)>>,mod)%mod)%mod;
printf("%lld\n",ans);
return ;
}
fup(i,,tot){
re int pk=p[i];
Get_fac_and_inv(min(t,pk),pk);
fup(k,st,ed)
w[i]=(w[i]+lucas(t,k,pk)*lucas(t-k,k-m,pk)%pk*lucas(t-*k+m,(t-*k+m-n)>>,pk)%pk)%pk;
}
printf("%lld\n",crt());
}
#include<bits/stdc++.h>
#define re register
#define int long long
using namespace std;
int T,n,m,mod,ans=,tot=,fac[],pi,pk,p;
inline int read(){
re int a=,b=;re char ch=getchar();
while(ch<''||ch>'')
b=(ch=='-')?-:,ch=getchar();
while(ch>=''&&ch<='')
a=(a<<)+(a<<)+(ch^),ch=getchar();
return a*b;
}
inline int qpow(re int a,re int b){
re int res=;a%=pk;
for(;b;b>>=){
if(b&)res=res*a%pk;
a=a*a%pk;
}
return res%pk;
}
inline int getcnt(re int x){
return x?x/pi+getcnt(x/pi):;
}
inline int getsum(re int x){
return x?((x/pk?qpow(fac[pk],x/pk):)*fac[x%pk]%pk*getsum(x/pi)%pk):;
}
inline int C(re int x,re int y){
if(y>x)return ;
re int a0=getsum(x),b0=getcnt(x);
re int a1=getsum(y),b1=getcnt(y);
re int a2=getsum(x-y),b2=getcnt(x-y);
b0-=b1+b2;
if(b0>=tot)return ;//含质因子的个数
return a0*qpow(a1,p-)%pk*qpow(a2,p-)%pk*qpow(pi,b0)%pk;
}
inline int work(){
re int res=,a,b,c,d;
fac[]=;
for(re int i=;i<=pk&&i<=T;i++)
fac[i]=(i%pi)?fac[i-]*i%pk:fac[i-];//处理阶乘
a=,b=n,c=(T-n-m)>>,d=(T+m-n)>>;//各方向初值
while(c>=){
res=(res+C(T,a+b)*C(a+b,a)%pk*C(c+d,c)%pk)%pk;
++a,++b,--c,--d;
}//处理组合数,上下左右的道路可能性
return res;
}
signed main(){
T=read(),mod=read(),n=read(),m=read();
n=(n<)?-n:n;m=(m<)?-m:m;//处理负数
re int l=mod;
for(re int i=;l>;i++){
if(i*i>l)i=l;//分解质因数
if(l%i==){
pi=i,pk=,tot=;
while(l%pi==)
l/=pi,pk*=pi,++tot;
p=pk/pi*(pi-);
(ans+=work()%mod*(mod/pk)%mod*qpow(mod/pk,p-)%mod)%=mod;//CRT
}
}
printf("%lld\n",ans);
return ;
}
另有 学习笔记“组合数取模”推荐
组合数取模(lucas定理+CRT合并)(AC)的更多相关文章
- 组合数取模&&Lucas定理题集
题集链接: https://cn.vjudge.net/contest/231988 解题之前请先了解组合数取模和Lucas定理 A : FZU-2020 输出组合数C(n, m) mod p (1 ...
- 组合数取模Lucas定理及快速幂取模
组合数取模就是求的值,根据,和的取值范围不同,采取的方法也不一样. 下面,我们来看常见的两种取值情况(m.n在64位整数型范围内) (1) , 此时较简单,在O(n2)可承受的情况下组合数的计算可以 ...
- hdu 3944 DP? 组合数取模(Lucas定理+预处理+帕斯卡公式优化)
DP? Problem Description Figure 1 shows the Yang Hui Triangle. We number the row from top to bottom 0 ...
- [转]组合数取模 Lucas定理
对于C(n, m) mod p.这里的n,m,p(p为素数)都很大的情况.就不能再用C(n, m) = C(n - 1,m) + C(n - 1, m - 1)的公式递推了. 这里用到Lusac定理 ...
- [hdu5226]组合数求和取模(Lucas定理)
题意:给一个矩阵a,a[i][j] = C[i][j](i>=j) or 0(i < j),求(x1,y1),(x2,y2)这个子矩阵里面的所有数的和. 思路:首先问题可以转化为求(0,0 ...
- hdu 3037 费马小定理+逆元除法取模+Lucas定理
组合数学推推推最后,推得要求C(n+m,m)%p 其中n,m小于10^9,p小于1^5 用Lucas定理求(Lucas定理求nm较大时的组合数) 因为p数据较小可以直接阶乘打表求逆元 求逆元时,由费马 ...
- BZOJ-1951 古代猪文 (组合数取模Lucas+中国剩余定理+拓展欧几里得+快速幂)
数论神题了吧算是 1951: [Sdoi2010]古代猪文 Time Limit: 1 Sec Memory Limit: 64 MB Submit: 1573 Solved: 650 [Submit ...
- BZOJ_2142_礼物_扩展lucas+组合数取模+CRT
BZOJ_2142_礼物_扩展lucas+组合数取模 Description 一年一度的圣诞节快要来到了.每年的圣诞节小E都会收到许多礼物,当然他也会送出许多礼物.不同的人物在小E 心目中的重要性不同 ...
- lucas定理解决大组合数取模
LL MyPow(LL a, LL b) { LL ret = ; while (b) { ) ret = ret * a % MOD; a = a * a % MOD; b >>= ; ...
随机推荐
- 左神算法进阶班8_1数组中累加和小于等于aim的最长子数组
[题目] 给定一个数组arr,全是正数:一个整数aim,求累加和小于等于aim的,最长子数组,要求额外空间复杂度O(1),时间复杂度O(N) [题解] 使用窗口: 双指针,当sum <= aim ...
- jqGrid的subGrid子表格
使用完整jqGrid作为子表格 使用子表格,涉及到jqGrid的三个选项: subGrid :首先必须将jqGrid的subGrid选项设置为true,默认为false:当此项设为true的时候,Gr ...
- Spring_关于@Resource注入为null解决办法
初学spring,我在dao层初始化c3p0的时候,使用@Resource注解新建对象是发现注入为null,告诉我 java.lang.NullPointerException. @Repositor ...
- Ionic login简单登录页面
1.login.html <ion-view view-title="登录" hide-nav-bar="true"> <div class= ...
- 19-10-24-H
H H H H H H ZJ一下: T1只会暴力,测试点分治. (表示作者的部分分并没有给够,暴力加部分表按测试点分类可以得60吧……) T2先直接手玩第一个子任务. 然后就$Find$了一个神奇的( ...
- keras multi-label classification 多标签分类
问题:一个数据又多个标签,一个样本数据多个类别中的某几类:比如一个病人的数据有多个疾病,一个文本有多种题材,所以标签就是: [1,0,0,0,1,0,1] 这种高维稀疏类型,如何计算分类准确率? 分类 ...
- Linux时间设置命令
1.date: 语法格式:date [-u] [-d datestr] [-s datestr] [--utc] [--universal] [--date=datestr] [--set=dates ...
- Kotlin 委托(2)变量委托是什么、自定义变量委托
1.委托是什么? 1.1 官网示例 在每个变量委托的实现的背后,Kotlin 编译器都会生成辅助对象并委托给它. 假设委托如下, class C { var prop: Type by MyDeleg ...
- 非常好理解的KNN算法示例
参考链接:https://www.joinquant.com/post/2227?f=study&m=math:一只兔子帮你理解KNN https://www.joinquant.com/po ...
- 一句话介绍python线程、进程和协程
一.进程: Python的os模块封装了常见的系统调用,其中就包括fork.而fork是linux常用的产生子进程的方法,简言之是一个调用,两个返回. 在python中,以下的两个模块用于进程的使用. ...