zoukankan      html  css  js  c++  java
  • 扩展卢卡斯定理

    解决的问题:
    (C_n^mpmod{p})(p)不是质数。
    (p)分解质数,假设为(p_1^{c_1}*p_2^{c_2}*...*p_k^{c_k})
    对每个(p_i^{c_i})求出在模意义下的(C_n^m),设为(a_i),我们的问题就变为:
    (egin{cases}xequiv a_1pmod{p_1^{c_1}}\ xequiv a_2pmod{p_2^{c_2}}\...\xequiv a_kpmod{p_k^{c_k}}end{cases})
    求这个(x)即为答案,因为模数互质,显然可以用CRT求。

    于是考虑求(C_n^mpmod{p_i^{c_i}})
    发现不能用逆元求(n!),因为不一定存在逆元,(x)存在逆元的条件为(gcd(x,p)=1)

    现在问题就是求(n!)在模(p_i^{c_i})的意义下的逆元,即求(n!)(p_i^{c_i})的值,考虑既然模数只有一个质因子,我们将(n!)中的质因子(p_i)提出,剩下的数必定与(p_i^{c_i})互质,exgcd求逆元即可。

    以下引用自

    (22!mod 3^2)为例:

    按照(3^2)分段:((1*2*3*4*5*6*7*8*9)*(10*11*12*13*14*15*16*17*18)*(19*20*21*22))

    将3提出后为((3^6*(1*2*3*4*5*6*7))*(1*2*4*5*7*8)*(10*11*13*14*16*17)*(19*20*22))

    观察发现前(lfloorfrac{n}{p_i^{c_i}} floor)模意义下相同,求一组时候快速幂即可。((19*20*22))直接暴力算。((1*2*3*4*5*6*7))递归即可。

    提出的(3)因子的数目可以直接算,为(sumlimits_{p^i<=n}lfloorfrac{n}{p^i} floor),证明见lyd蓝书。

    于是求完了。

    模板题

    code:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxp=1000010;
    typedef long long ll;
    ll n,m,mod;
    ll fac[maxp];
    inline ll power(ll x,ll k,ll mod)
    {
    	ll res=1%mod;
    	while(k)
    	{
    		if(k&1)res=res*x%mod;
    		x=x*x%mod;k>>=1;
    	}
    	return res;
    }
    ll calc(ll x,ll p,ll mod)
    {
    	if(x<=1)return 1;
    	ll res=1;
    	if(x>=mod)res=power(fac[mod-1],x/mod,mod);
    	if(x%mod)res=res*fac[x%mod]%mod;
    	return res*calc(x/p,p,mod)%mod;
    }
    void exgcd(ll a,ll b,ll& x,ll& y)
    {
    	if(!b){x=1,y=0;return;}
    	exgcd(b,a%b,x,y);
    	ll z=x;x=y,y=z-(a/b)*y;
    }
    inline ll inv(ll a,ll mod)
    {
    	if(!a)return 0;
    	ll x,y;exgcd(a,mod,x,y);
    	x=(x%mod+mod)%mod;
    	return x;
    }
    inline ll C(ll n,ll m,ll p,ll mod)
    {
    	if(m>n)return 0;
    	fac[0]=1;
    	for(ll i=1;i<mod;i++)fac[i]=fac[i-1]*((i%p)?i:1)%mod;
    	ll a=calc(n,p,mod),b=inv(calc(m,p,mod),mod),c=inv(calc(n-m,p,mod),mod);
    	ll res=a*b%mod*c%mod;
    	int cnt=0;
    	for(ll i=p;i<=n;i*=p)cnt+=n/i;
    	for(ll i=p;i<=m;i*=p)cnt-=m/i;
    	for(ll i=p;i<=n-m;i*=p)cnt-=(n-m)/i;
    	//cerr<<cnt<<endl;
    	return res*power(p,cnt,mod)%mod;
    }
    int main()
    {
    	//freopen("test.in","r",stdin);
    	//freopen("test.out","w",stdout);
    	scanf("%lld%lld%lld",&n,&m,&mod);
    	ll tmp=mod,ans=0;
    	for(ll i=2;i*i<=tmp;i++)
    	{
    		if(tmp%i)continue;
    		ll now=1;
    		while(tmp%i==0)now*=i,tmp/=i;
    		ans=(ans+C(n,m,i,now)*(mod/now)%mod*inv(mod/now,now)%mod)%mod;
    	}
    	if(tmp>1)ans=(ans+C(n,m,tmp,tmp)*(mod/tmp)%mod*inv(mod/tmp,tmp)%mod)%mod;
    	printf("%lld",(ans%mod+mod)%mod);
    	return 0;
    }
    
  • 相关阅读:
    Leetcode 15 3Sum
    Leetcode 383 Ransom Note
    用i个点组成高度为不超过j的二叉树的数量。
    配对问题 小于10 1.3.5
    字符矩阵的旋转 镜面对称 1.2.2
    字符串统计 连续的某个字符的数量 1.1.4
    USACO twofive 没理解
    1002 All Roads Lead to Rome
    USACO 5.5.1 求矩形并的周长
    USACO 5.5.2 字符串的最小表示法
  • 原文地址:https://www.cnblogs.com/nofind/p/11929825.html
Copyright © 2011-2022 走看看