您的位置:首页 > 其它

hdu5446 lucas+crt

2015-09-15 20:50 176 查看
题意:一个大的组合数模一个大的合数,这个合数可以拆成互不相同的质数。

众所周知,大的组合数模一个素数可以用lucas定理做,模合数,只需要用这个组合数模这个合数的质因数,再用crt反推回去就可以得到答案。
http://blog.csdn.net/acdreamers/article/details/8037918 http://blog.csdn.net/acdreamers/article/details/30992367
这个方法是以前从大神博客里看到的,没想到居然用上了。
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
long long f[100010];
long long m,n,k;
long long p[15],a[15];
long long mod_pow(int a,int n,int p)
{
    long long ret=1;
    long long A=a;
    while(n)
    {
        if(n&1) ret=(ret*A)%p;
        A=(A*A)%p;
        n>>=1;
    }
    return ret;
}
void init(long long p)
{
    f[0]=1;
    for(int i=1;i<=p;i++)
        f[i]=f[i-1]*i%p;
}
long long Lucas(long long a,long long k,long long p)
{
    long long re=1;
    while(a&&k)
    {
        long long aa = a%p;long long bb = k%p;
        if(aa < bb) return 0;
        re = re*f[aa]*mod_pow(f[bb]*f[aa-bb]%p,p-2,p)%p;
        a/=p;
        k/=p;
    }
    return re;
}
void ext_gcd(ll a,ll b,ll &d,ll &x,ll &y)
{
    if(!b)
    {
        x=1;y=0;d=a;
        return ;
    }
    else
    {
        ext_gcd(b,a%b,d,y,x);
        y-=a/b*x;
    }
}
long long M;///x=a[i](mod m[i])
ll mul(ll x,ll y,ll mod)
{
    long long ret=0;
    while(y){
        if(y&1)ret=(ret+x)%mod;
        x=(x+x)%mod;
        y>>=1;
    }
    return ret;
}
long long China(int r)
{
    M=1;
    for(int i=0;i<r;i++) M*=p[i];
    long long ans=0;
    for(int i=0;i<r;i++){
        long long Mi=M/p[i],d,x0,y0;
        ext_gcd(Mi,p[i],d,x0,y0);
        ans=(ans+mul(x0,mul(a[i],Mi,M),M))%M;
    }
    ans=(ans%M+M)%M;
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%I64d%I64d%I64d",&m,&n,&k);
        for(int i=0;i<k;i++)
        {
            scanf("%I64d",&p[i]);
            init(p[i]);
            a[i]=Lucas(m,n,p[i]);
        }
        long long ans=China(k);
        printf("%I64d\n",ans);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: