1951: [Sdoi2010]古代猪文|数论大合集

做这个题大概需要直到以下姿势:快速幂,费马小定理,卢卡斯定理,中国剩余定理。(大概也就这些

题目大概是让求

gd|nCdnmodp

然后根据费马小定理原式
=gd|nCdnmod(p1)modp

然后也就是要求指数上的这个东西 d|nCdnmod(p1)
然后 p1 还不是质数。。需要分解成质因子然后用中国剩余定理合并,然后还要求组合数还要卢卡斯定理,最后特判一下 g=p 的情况

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define ll long long
#define mod 999911659 //2 3 4679 35617
#define N 100001
using namespace std;
int sc()
{
    int i=0,f=1; char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar();
    return i*f;
}
ll ans[4],fac[4][35666],inv[4][35666],p[4]={2,3,4679,35617};
ll n,g,a;
void pre()
{
    for(int i=0;i<4;i++)
    {
        fac[i][0]=inv[i][0]=fac[i][1]=inv[i][1]=1;
        for(int j=2;j<p[i];j++)
            fac[i][j]=fac[i][j-1]*j%p[i],
            inv[i][j]=inv[i][p[i]%j]*(p[i]-p[i]/j)%p[i];
        for(int j=2;j<p[i];j++)
            inv[i][j]=inv[i][j]*inv[i][j-1]%p[i];
    }
}
ll C(ll n,ll m,int i)
{
    if(n<m)return 0;
    if(n<p[i]&&m<p[i])return fac[i][n]*inv[i][m]*inv[i][n-m]%p[i];
    return C(n/p[i],m/p[i],i)*C(n%p[i],m%p[i],i)%p[i]; } void solve(ll m) { for(int i=0;i<4;i++) ans[i]=(ans[i]+C(n,m,i))%p[i]; } void ex_gcd(ll x,ll y,ll &a,ll &b) { if(x==0){a=0,b=1;return;} ex_gcd(y%x,x,b,a); a-=b*(y/x);
}
int cal(ll x,int y)
{
    ll ans=1;
    for(;y;x=x*x%mod,y>>=1)
        if(y&1)ans=ans*x%mod;
    return ans;
}
int main()
{
    pre();n=sc(),g=sc();a=sqrt(n);
    if(g==mod){puts("0");return 0;}
    for(int i=1;i<=a;i++)
        if(n%i==0)
        {
            solve(i);
            if(i*i!=n)solve(n/i);
        }
    for(int i=0;i<3;i++)
    {
        ll p1=p[i],p2=p[i+1],k1,k2;
        p[i+1]=p[i+1]*p[i];
        ex_gcd(p1,p2,k1,k2);
        k1=k1%p2*(ans[i+1]-ans[i]);
        ans[i+1]=(k1*p1+ans[i])%p[i+1];
    }
    printf("%d\n",cal(g,(ans[3]+p[3])%p[3]));
    return 0;
}

你可能感兴趣的:(中国剩余定理,卢卡斯定理)