BZOJ1951 [Sdoi2010]古代猪文 NOIP数论大杂烩

https://www.lydsy.com/JudgeOnline/problem.php?id=1951

Description

  猪王国的文明源远流长,博大精深。

  iPig在大肥猪学校图书馆中查阅资料,得知远古时期猪文文字总个数为N。当然,一种语言如果字数很多,字典也相应会很大。当时的猪王国国王考虑到如果修一本字典,规模有可能远远超过康熙字典,花费的猪力、物力将难以估量。故考虑再三没有进行这一项劳猪伤财之举。当然,猪王国的文字后来随着历史变迁逐渐进行了简化,去掉了一些不常用的字。

  iPig打算研究古时某个朝代的猪文文字。根据相关文献记载,那个朝代流传的猪文文字恰好为远古时期的k分之一,其中k是N的一个正约数(可以是1和N)。不过具体是哪k分之一,以及k是多少,由于历史过于久远,已经无从考证了。

  iPig觉得只要符合文献,每一种能整除N的k都是有可能的。他打算考虑到所有可能的k。显然当k等于某个定值时,该朝的猪文文字个数为N / k。然而从N个文字中保留下N / k个的情况也是相当多的。iPig预计,如果所有可能的k的所有情况数加起来为P的话,那么他研究古代文字的代价将会是G的P次方。

  现在他想知道猪王国研究古代文字的代价是多少。由于iPig觉得这个数字可能是天文数字,所以你只需要告诉他答案除以999911659的余数就可以了。

Input

 输入有一行:两个数N、G,用一个空格分开。

Output

 输出有一行:一个数,表示答案除以999911659的余数。

Sample Input

4 2

Sample Output

2048

HINT

【数据规模】
  10%的数据中,1 <= N <= 50;
  20%的数据中,1 <= N <= 1000;
  40%的数据中,1 <= N <= 100000;
  100%的数据中,1 <= G <= 1000000000,1 <= N <= 1000000000。

此题用到了NOIP数论$\frac{2}{3}\qquad$的知识。

有费马小定理,Lucas定理,龟速幂,线性推逆元,扩展GCD,中国剩余定理,分解质因数的内容,一个一个来。

题目显然是让我们求Gd|n Cdn   moP

因为P是一个质数,显然费马小定理成立ap-1 ≡ 1

之后G上面的数可以化成∑d|n Cdn(mod P-1)

999911658=2 × 3 × 4679 × 35617.

可以一层扩展Lucas,用中国剩余定理扩展之后合并,需要线性推逆元和扩展GCD。

之后分解质因数,龟速幂就好了!

#include<cstdio>
#define mod 999911659
#define N 50000
typedef long long ll;
ll in[5]={0,2,3,4679,35617};
ll M[N+2];
ll a[N+2];
ll n,G;
ll fac[N+2][5];
ll inv[N+2][5];
ll m=mod-1;
ll div[N+2];
ll idx;
ll ans2;
void init()
{
    for(int j=1;j<=4;j++)
    {
        fac[0][j]=1;
        inv[in[j]-1][j]=in[j]-1;
        for(int i=1;i<=in[j];i++)
            fac[i][j]=(fac[i-1][j]*i)%in[j];
        for(int i=in[j]-2;i>=0;i--)
            inv[i][j]=(inv[i+1][j]*(i+1))%in[j];    
    }
}
ll pow(ll x,ll y)
{
    ll ans3=1;
    while(y)
    {
        if(y&1)
            ans3=(ans3*x)%mod;
        x=(x*x)%mod;
        y/=2;
    }
    return ans3;
}
ll lucas(ll n,ll m,ll i)
{
    if(n<m)
        return 0;
    if(n<in[i]&&m<in[i])
        return fac[n][i]*inv[m][i]%in[i]*inv[n-m][i]%in[i];
    else
        return lucas(n/in[i],m/in[i],i)%in[i]*lucas(n%in[i],m%in[i],i)%in[i];
}
void exgcd(ll a,ll b,ll &x,ll &y)
{
    if(!b)
    {
        x=1;
        y=0;
        return;
    }
    exgcd(b,a%b,x,y);
    ll tmp=x;
    x=y;
    y=tmp-a/b*y;
    return;
}
ll China()
{
    ll ans=0,x,y;
    for(int i=1;i<=4;i++)
    {
        M[i]=m/in[i];
        exgcd(M[i],in[i],x,y);
        ans=(ans+a[i]*x*M[i])%m;
    }
    return (ans+m)%m;
}
int main()
{
    scanf("%lld%lld",&n,&G);
    if(G==mod)
    {
        puts("0");
        return 0;
    }
    init();
    div[++idx]=1; 
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            div[++idx]=i;
            if((i*i)!=n)
                div[++idx]=n/i;            
        }
    }
    div[++idx]=n;
    for(int i=1;i<=idx;i++)
    {
        for(int j=1;j<=4;j++)
            a[j]=lucas(n,div[i],j);
        ans2=(ans2+China())%m;
    }
    ll ans=pow(G,ans2)%mod;
    printf("%lld",ans);
}

  

posted @ 2018-10-26 13:04  342  阅读(220)  评论(0编辑  收藏  举报