• [SDOI2010]古代猪文 (欧拉,卢卡斯,中国剩余)


    [SDOI2010]古代猪文



    $ solution: $

    这道题感觉综合性极强,用到了许多数论中的知识:

    1. 质因子,约数,组合数
    2. 欧拉定理
    3. 卢卡斯定理
    4. 中国剩余定理

    首先我们读题,发现题目需要我们枚举k(就是n的所有约数),并且对于每一个k都要用一个组合数算出其情况数(读题:不过具体是哪k分之一。这句话说明我们可以从n中取出任意k个字,所以情况数就是 $ C(_n^k) $ )(然后因为我们求的组合数范围有点大,所以需要用卢卡斯定理来求组合数(接下来我们会发现模数其实比较小))。但是这道题目把所有情况数(设有tot个情况),求为 $ G^{tot} $ 作答案输出。

    众所周知,指数是不能直接取模的,所以我们要用到欧拉定理(注意欧拉定理建立在 $ gcd(G,999911659)=1 $ 的情况下,所以读入时要特判!)。

    $ G^{tot}=G^{(tot mod phi(P)+phi(P))} mod(P) $

    因为我们的模数为999911659(质数),所以我们其实就是要求这个东西:

    $ G^{(tot mod 999911658+999911658)} $

    但是我们发现虽然我们现在可以取模了,但是999911658并不是一个质数,而我们求tot的时候是需要用卢卡斯的,所以我们必须保证模数是一个质数且不能太大。所以我们又得用上中国剩余定理, $ 999911658=2 imes 3 imes 4679 imes 35617 $

    于是我们分别求出在 $ mod 2 ,mod 3,mod 4679,mod 35617 $ 意义下的所有tot,然后就需要中国剩余定理解出我们真正的 $ mod 999911658 $ 意义下的tot是多少,然后就可以直接搞快速幂求答案了!



    $ code: $

    #include<iostream>
    #include<cstdio>
    #include<iomanip>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<ctime>
    #include<cmath>
    #include<vector>
    #include<queue>
    #include<map>
    #include<set>
    
    #define ll long long
    #define db double
    #define mod 999911658
    #define rg register int
    
    using namespace std;
    
    ll n,g,ans;
    ll a[4];
    ll jc[40005];
    ll m[4]={2,3,4679,35617};
    
    inline ll qr(){
        char ch;
        while((ch=getchar())<'0'||ch>'9');
        ll res=ch^48;
        while((ch=getchar())>='0'&&ch<='9')
            res=res*10+(ch^48);
        return res;
    }
    
    inline ll ksm(ll x,ll y,ll p){
        ll res=1; x%=p;
        while(y){
            if(y&1)res=res*x%p;
            x=x*x%p; y>>=1;
        }return res;
    }
    
    inline ll c(ll x,ll y,ll p){ //组合数
        if(x<y)return 0;
        return jc[x]%p*ksm(jc[y],p-2,p)%p*ksm(jc[x-y],p-2,p)%p;//现求逆元
    }
    
    inline ll lc(ll x,ll y,ll p){ //卢卡斯
        if(x<y)return 0; if(!x)return 1;
        return c(x%p,y%p,p)*lc(x/p,y/p,p)%p;
    }
    
    int main(){
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
        n=qr(); g=qr();
        if(n==mod+1||g==mod+1){//特判
            puts("0"); return 0;
        }
        for(rg k=0;k<4;++k){ jc[0]=jc[1]=1; //
            for(rg i=2;i<=40000;++i)jc[i]=jc[i-1]*i%m[k]; //求出阶乘
            for(rg i=1,j=sqrt(n);i<=j;++i){ //枚举约数
                if(n%i!=0)continue;
                a[k]=(a[k]+lc(n,i,m[k]))%m[k];
                if(n==i*i)continue;
                a[k]=(a[k]+lc(n,n/i,m[k]))%m[k];//n/i是较大的约数
            }
        }
        for(rg i=0;i<4;++i)
            ans=(ans+a[i]*(mod/m[i])%mod*ksm(mod/m[i],m[i]-2,m[i]))%mod;//中国剩余定理
        printf("%lld
    ",ksm(g,ans,mod+1));
        return 0;
    }
    
    
  • 相关阅读:
    2014年10月20----数组1
    类型--2014年10月19日
    2014年10月17----类别
    2014年10月16号--for语句实例
    2014年10月12日——运算符
    java练习题:解一元二次方程、判断闰年、判断标准身材、三个数取最大值
    Java安装与环境配置
    SQL语言增加、修改、删除数据的语法
    StringBuffer的用法(转)
    JSTL标签库简介
  • 原文地址:https://www.cnblogs.com/812-xiao-wen/p/10698494.html
Copyright © 2020-2023  润新知