欢迎大家访问我的老师的OJ———caioj.cn
题目描述
传送门
(“在那山的那边海的那边有一群小肥猪。他们活泼又聪明,他们调皮又灵敏。他们自由自在生活在那绿色的大草坪,他们善良勇敢相互都关心……” )xswl
思路
一句话题意:给定整数 q , n ( 1 ≤ q , n ≤ 1 0 9 ) q,n(1\le q,n\le 10^9) q,n(1≤q,n≤109),计算 q ∑ d ∣ n C n d ( mod 999911659 ) . q^{\sum_{d\mid n}C_n^d}(\operatorname{mod} 999911659). q∑d∣nCnd(mod999911659).
首先先拿部分分, q = 999911659 q=999911659 q=999911659时,直接输出" 0 0 0".
否则,因为
999911659
999911659
999911659是质数,所以q,n互质。由欧拉定理的推论得:
q
∑
d
∣
n
C
n
d
≡
q
∑
d
∣
n
C
n
d
mod
999911658
(
mod
999911659
)
\large\ q^{\sum_{d\mid n}C_n^d}\equiv q^{\sum_{d\mid n}C_n^d\operatorname{mod}999911658}(\operatorname{mod} 999911659)
q∑d∣nCnd≡q∑d∣nCndmod999911658(mod999911659)
因此我们只要求出 ∑ d ∣ n C n d mod 999911658 \sum_{d\mid n}C_n^d\operatorname{mod}999911658 ∑d∣nCndmod999911658即可。
将 999911658 999911658 999911658分解质因数,得到: 999911658 = 2 x 3 x 4679 x 35617 999911658=2\operatorname{x}3\operatorname{x}4679\operatorname{x}35617 999911658=2x3x4679x35617。
我们可以枚举 n n n的约数 d d d,然后运用Lucas定理,求组合数 C n d C_n^d Cnd,分别计算出 ∑ d ∣ n C n d \sum_{d\mid n}C^d_n ∑d∣nCnd对 2 , 3 , 4679 , 35617 2,3,4679,35617 2,3,4679,35617四个质数取模的结果,记为 a 1 , a 2 , a 3 , a 4 a_1,a_2,a_3,a_4 a1,a2,a3,a4。计算过程中,对于一个质数p,可以预处理p以内的所有阶乘以及阶乘的模p乘法逆元,从而快速计算组合数。
最后,用中国剩余定理求解线性同余方程组:
{
x
mod
2
=
a
1
x
mod
3
=
a
2
x
mod
4679
=
a
3
x
mod
35671
=
a
4
\begin{cases}x\operatorname{mod}2=a_1\\x\operatorname{mod} 3=a_2\\x\operatorname{mod}4679=a_3\\x\operatorname{mod}35671=a_4\end{cases}
⎩⎪⎪⎪⎨⎪⎪⎪⎧xmod2=a1xmod3=a2xmod4679=a3xmod35671=a4
得到 ∑ d ∣ n C n d mod 999911658 \sum_{d\mid n}C_n^d\operatorname{mod}999911658 ∑d∣nCndmod999911658的最小非负整数解 x x x。再用快速幂求 q x q^x qx即可。
AC code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define ll long long
#define gc getchar()
using namespace std;
const ll P=999911659;
ll p[5]={0,2,3,4679,35617},m[5],t[5];
ll pn[5][35617][2]={{},{{1,1},{1,1}},{{1,1},{1,1},{2,2}},{{1,1},{1,1}},{{1,1},{1,1}}};
inline void qr(ll &x)
{
x=0;ll f=1;char c=gc;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
x*=f;
}
void qw(ll x)
{
if(x/10)qw(x/10);
putchar(x%10+48);
}
inline ll pow_mod(ll a,ll b,ll c)
{
ll ans=1;a%=c;
b%=(c-1);//费马小定理
while(b)
{
if(b&1)ans=ans*a%c;
b>>=1;a=a*a%c;
}
return ans;
}
inline ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b){x=1;y=0;return a;}
ll tx,ty;ll d=exgcd(b,a%b,tx,ty);
x=ty;y=tx-(a/b)*ty;
return d;
}
ll C(ll d,ll n,ll i)//Lucas
{
if(d<p[i]&&n<p[i])
return pn[i][n][0]*pn[i][d][1]*pn[i][n-d][1]%p[i];
return C(d%p[i],n%p[i],i)*C(d/p[i],n/p[i],i);
}
inline void pre()
{
for(int i=2;i<p[3];i++)
{
pn[3][i][0]=pn[3][i-1][0]*i%p[3];
pn[3][i][1]=pow_mod(pn[3][i][0],p[3]-2,p[3]);
}
for(int i=2;i<p[4];i++)
{
pn[4][i][0]=pn[4][i-1][0]*i%p[4];
pn[4][i][1]=pow_mod(pn[4][i][0],p[4]-2,p[4]);
}
for(int i=1;i<=4;i++)
{
m[i]=(P-1)/p[i];
ll x,y;exgcd(m[i],p[i],x,y);
t[i]=x;
}
}
int main()
{
ll n,q;qr(n),qr(q);
q%=P;
if(!q){puts("0");return 0;}
pre();
ll a[5]={0,0,0,0,0};
for(ll d=1;d*d<=n;d++)
if(n%d==0)
{
for(int i=1;i<=4;i++)
{
a[i]=(a[i]+C(d,n,i))%p[i];
if(d*d!=n)a[i]=(a[i]+C(n/d,n,i))%p[i];
}
}
ll ans=0;
for(int i=1;i<=4;i++)
ans=(a[i]*m[i]%(P-1)*t[i]%(P-1)+ans)%(P-1);
ans=(ans+(P-1))%(P-1);
qw(pow_mod(q,ans,P));puts("");
return 0;
}