【BZOJ】1951[Sdoi2010]古代猪文

【题意】给定G,N,求:

$$ans=G^{\sum_{i|n}\binom{n}{i}}\ \mod\ \ p$$

1<=N,G<=10^9,p=999911659。

【算法】欧拉定理+组合数取模(lucas)+中国剩余定理(CRT)

【题解】

先考虑简化幂运算,因为模数为素数,由欧拉定理可知G^k=G^(k%φ(p)) mod p,显然G^(k%φ(p)) mod p可以用快速幂求解

但是欧拉定理要求(G,p)=1,当G=p时不满足条件,可以特判答案为0或者用扩展欧拉定理(b%φ(p)+(b>=φ(p)?φ(p):0))。

故我们实际要求:

$$\sum_{i|n}\binom{n}{i}\ \mod\ \ (p-1)$$

因为p是素数,φ(p)=p-1=999911658=2*3*4679*35617。

因为p-1分解后无平方因子,所以直接用lucas分别对素模数计算后用中国剩余定理合并即可(若有则需要参考bzoj礼物的方法——扩展lucas)

#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=100010,MOD=999911659;//999911658=2*3*4679*35617
const int p[5]={0,2,3,4679,35617};
ll a[5],fac[5][maxn],n,G;
ll power(ll x,ll k,ll p)
{
    if(x==0)return 0;
    ll ans=1;//快速幂ans=1! 
    while(k>0)
    {
        if(k&1)ans=(ans*x)%p;//满足1时才累乘 
        x=(x*x)%p;
        k>>=1;
    }
    return ans;
}
ll C(ll n,ll m,ll k)
{
    if(n<m)return 0;
    return fac[k][n]*power(fac[k][m],p[k]-2,p[k])%p[k]*power(fac[k][n-m],p[k]-2,p[k])%p[k];//n!/m!/(n-m)!
}    
ll lucas(ll n,ll m,ll k)
{
    if(n<m)return 0;
    if(n<p[k]&&m<p[k])return C(n,m,k);
    return C(n%p[k],m%p[k],k)*lucas(n/p[k],m/p[k],k)%p[k];
}
int main()
{
    scanf("%lld%lld",&n,&G);
    if(G==MOD)
    {
        printf("0");
        return 0;
    }
    for(int k=1;k<=4;k++)
    {
        fac[k][0]=1;
        for(int i=1;i<p[k];i++)fac[k][i]=fac[k][i-1]*i%p[k];//随时记得取模 
    }
    for(int i=1;i*i<=n;i++)if(n%i==0)
    {
        int j=n/i;
        for(int k=1;k<=4;k++)
        {
            a[k]=(a[k]+lucas(n,i,k))%p[k];
            if(i!=j)a[k]=(a[k]+lucas(n,j,k))%p[k];
        }
    }
    ll M=MOD-1;
    ll ans=0;
    for(int k=1;k<=4;k++)ans=(ans+a[k]*M/p[k]*power(M/p[k],p[k]-2,p[k]))%M;
    printf("%lld",power(G,ans,MOD));
    return 0;
}
View Code

 

posted @ 2017-07-17 16:22  ONION_CYC  阅读(390)  评论(0编辑  收藏  举报