Hdu 5446 Unknown Treasure(Lucas+中国剩余定理)

58 篇文章 0 订阅
2 篇文章 0 订阅

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=5446

思路:Lucas求出所有a[i]=C(n,m)%m[i],中国剩余定理求出最终结果x (LL*LL会爆掉,手写乘法)。

中国剩余定理:

m1,m2,....mn是两两互质的正整数,对任意给定的整数a1,a2,....an必存在整数,满足

        xa1 (mod m1),xa2 (mod m2)xa3 (mod m3)......

并且满足上列方程组的解x(mod m1m2m3.....mn)是存在唯一的。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
int k;
LL n,m;
LL p[15],a[15];
LL fac[100005];
LL qmul(LL x,LL y,LL mod)
{
    x=(x%mod+mod)%mod;
    y=(y%mod+mod)%mod;
    LL ret=0;
    while(y)
    {
        if(y&1) ret=(ret+x)%mod;
        x=x*2%mod;
        y>>=1;
    }
    return ret;
}
LL extgcd(LL a,LL b,LL& x,LL& y)
{
    LL d,t;
    if(!b)
    {
        x=1;
        y=0;
        return a;
    }
    d=extgcd(b,a%b,x,y);
    t=x;
    x=y;
    y=t-a/b*y;
    return d;
}
LL CRT()
{
    LL M=1,ans=0,x,y;
    for(int i=1; i<=k; i++) M*=p[i];
    for(int i=1; i<=k; i++)
    {
        LL mi=M/p[i];
        extgcd(mi,p[i],x,y);
        ans=(ans+qmul(qmul(mi,x,M),a[i],M))%M;
    }
    if(ans<0) ans=ans+M;
    return ans;
}
LL PowMod(LL a,LL b,LL mod)
{
    LL ret=1;
    while(b)
    {
        if(b&1) ret=(ret*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return ret;
}
void Get_Fac(LL mod)
{
    fac[0]=1;
    for(int i=1;i<=mod;i++)
        fac[i]=(fac[i-1]*i)%mod;
}
LL Lucas(LL n,LL m,LL p)
{
    LL ret=1;
    while(n&&m)
    {
        LL a=n%p,b=m%p;
        if(a<b) return 0;
        ret=(ret*fac[a]*PowMod(fac[b]*fac[a-b]%p,p-2,p))%p;
        n/=p,m/=p;
    }
    return ret;
}
int main()
{
    int t;
    ios::sync_with_stdio(0);
    cin>>t;
    while(t--)
    {
        cin>>n>>m>>k;
        memset(a,0,sizeof(a));
        for(int i=1; i<=k; i++)
        {
            cin>>p[i];
            Get_Fac(p[i]);
            a[i]=Lucas(n,m,p[i]);
        }
        cout<<CRT()<<endl;
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值