题解 P2480 【[SDOI2010]古代猪文】
Notshgiook · · 题解
这是一道数论全家桶!!
前言:这是一道十分有趣的数论题!!可以说是基础数论全家桶!!
虽然钟长者说,见到输入几个数,输出一个数,应该果断选择一种古老而又优秀的算法——打表!!!但是还是果断的去莽这个题
内置数论知识:欧拉-费马定理,
话不多说,现在开始 口胡 ta!\ !\ !
当然这题面又臭又长,显然需要把题面化简一下子啦!!!
存在一个整数
最终的答案就是:
首先检验一下
盲猜这个指数非常大,所以不如先来考虑一波欧拉定理!
欧拉定理
当
这里的
欧拉定理的正确性,弱弱的本人也不会,还请各位爷去问“无所不知无所不能”的度娘!!
废话,这太显然了!!!!
但是这样我们发现,我们的问题变成了一个组合数取模问题!!!
想想组合数取模能怎么做??
即:
那么在模
对于证明,本人太多,请各位神仙前往度娘!!
那么我们显然可以,将
最终答案即为:
那么构建出来的同余方程组长什么样子呢???
当然对于每一个同余方程可以先用取模的性质化简化简!!!
在这里我们发现,对于每个组合数
Lucas 定理
当且仅当
弱弱的本人根本不会证明,还请各位大神询问度娘
中间还存在一些小细节,比如求组合数可用民间的提前预处理每个数的阶乘和每个数阶乘的逆元,然后每次求组合数变成了一次
所以这篇鬼畜的古代猪文就能告一段落了,这可真是一道数论好题。费马-欧拉定理,
Code Below
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define Mod 999911659
#define mod 999911658
#define maxn 40005
typedef long long ll;
ll n,g;
ll d[maxn],tot;
ll p[10],cnt;
inline ll qpow(ll a,ll k,ll p)
{
ll res=1;
while(k)
{
if(k&1) res=(res*a)%p;
a=(a*a)%p;
k>>=1;
}
return res%p;
}
ll fac[maxn],inv[maxn];
inline void init(ll p)
{
fac[0]=1;
for(register int i=1;i<p;i++)
fac[i]=fac[i-1]*i%p;
inv[p]=0;
inv[p-1]=qpow(fac[p-1],p-2,p);
for(register int i=p-2;i>=0;i--)
inv[i]=inv[i+1]*(i+1)%p;
}
inline ll C(ll n,ll m,ll p)
{
if(m>n) return 0;
return fac[n]*inv[m]%p*inv[n-m]%p;
}
inline ll Lucas(ll n,ll m,ll p)
{
if(m==0) return 1;
return Lucas(n/p,m/p,p)*C(n%p,m%p,p)%p;
}
ll a[10];
inline void calc(int x)
{
init(p[x]);
for(register int i=1;i<=tot;i++)
a[x]=(a[x]+Lucas(n,d[i],p[x]))%p[x];
}
inline ll CRT()
{
ll ans=0;
for(register int i=1;i<=cnt;i++)
{
ll M=mod/p[i],t=qpow(M,p[i]-2,p[i]);
ans=(ans+a[i]%mod*t%mod*M%mod)%mod;
}
return (ans+mod)%mod;
}
int main()
{
scanf("%lld%lld",&n,&g);
if(g%Mod==0)
{
printf("0\n");
return 0;
}
ll t=mod;
for(register int i=2;i*i<=mod;i++)
{
if(t%i==0)
{
p[++cnt]=i;
while(t%i==0) t=t/i;
}
}
if(t!=1) p[++cnt]=t;
for(register int i=1;i*i<=n;i++)
{
if(n%i==0)
{
d[++tot]=i;
if(i*i!=n) d[++tot]=n/i;
}
}
for(register int i=1;i<=cnt;i++) calc(i);
printf("%lld",qpow(g,CRT(),Mod));
return 0;
}