传送门:bzoj1951
此题考到的知识点比较多,首先得看出这是个 CRT C R T 。
由欧拉定理,当 n⊥p n ⊥ p 时, nϕp≡n (mod p) n ϕ p ≡ n ( m o d p ) .
此题即求 G∑d|n(nd)(mod p−1) (mod p) G ∑ d | n ( n d ) ( m o d p − 1 ) ( m o d p ) 的值。
n≤109 n ≤ 10 9 ,所以 (nd) ( n d ) 可用卢卡斯定理求得:
p为素数时, (nm)≡(⌊np⌋⌊mp⌋)(n mod pm mod p) (mod p) ( n m ) ≡ ( ⌊ n p ⌋ ⌊ m p ⌋ ) ( n m o d p m m o d p ) ( m o d p )
还得线性推一下逆元。
这里的 p−1(999911658) p − 1 ( 999911658 ) 不是素数,但它可以拆分成 999911658=2∗3∗4679∗35617 999911658 = 2 ∗ 3 ∗ 4679 ∗ 35617 的形式。这样我们可以对四个素因数分别计算,最后通过 CRT C R T 求得最终在 p−1 p − 1 模意义下的幂次,再快速幂即可。
CRT C R T 求出的解可以证明,具有唯一性。
CRT C R T (中国剩余定理):求得满足
x≡a1(mod p1) x ≡ a 1 ( m o d p 1 )
x≡a2(mod p2) x ≡ a 2 ( m o d p 2 )
…
x≡an(mod pn) x ≡ a n ( m o d p n )
的最小正整数 x x 。( p1 p 1 ~ pn p n 为两两互不相同的素数)
设 M=∏ni=1pi M = ∏ i = 1 n p i , Mi=Mpi M i = M p i , ti≡M−1i (mod pi) t i ≡ M i − 1 ( m o d p i )
可以得到 x=∑ni=1Mitiai (mod M) x = ∑ i = 1 n M i t i a i ( m o d M )
注意:
此题有一种特殊情况,因为欧拉定理只在n,p互质情况下成立,当 n≡0(mod p) n ≡ 0 ( m o d p ) 时,直接输出0即可。(其实求一遍快速幂也不会错,但乘的过程中,默认 00=1 0 0 = 1 ,所以会WA一个点,需要特判一下)
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=35620,mod=999911659;
int l[4][N],iv[4][N],p[4]={2,3,4679,35617},m[4];
int n,G;
inline int fp(int a,int b,int mod)
{if(!a) return 0;
int ret=1;for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) ret=1ll*ret*a%mod;return ret;}
inline int CRT()
{
int M=mod-1,ans=0,res;
for(int i=0;i<4;++i){
res=1ll*M/p[i]*fp(M/p[i],p[i]-2,p[i])%M*m[i]%M;
ans=(1ll*ans+res)%M;
}
return ans;
}
inline int lucas(int x,int y,int id)
{
if(!y) return 1;
if(xif(y>x) return 0;
return 1ll*l[id][x]*iv[id][y]%p[id]*iv[id][x-y]%p[id];
}else return 1ll*lucas(x/p[id],y/p[id],id)*lucas(x%p[id],y%p[id],id)%p[id];
}
int main(){
int i,j,k;
scanf("%d%d",&n,&G);G%=mod;
// if(G==0){printf("0\n");return 0;}
for(i=0;i<4;++i) iv[i][0]=l[i][0]=iv[i][1]=1;
for(i=1;i<4;++i)
for(j=1;j
1ll*l[i][j-1]*j%p[i];
if(j>1) iv[i][j]=1ll*(p[i]-p[i]/j)*iv[i][p[i]%j]%p[i];
}
for(i=1;i<4;++i)
for(j=1;j
1ll*iv[i][j]*iv[i][j-1]%p[i];
for(i=1;i*i<=n;++i){
if(n%i==0){
m[0]=(m[0]+((n|i)==n))%2;
for(j=1;j<4;++j) m[j]=(1ll*m[j]+lucas(n,i,j))%p[j];
if(i*i!=n) {
m[0]=(m[0]+((n|(n/i))==n))%2;
for(j=1;j<4;++j) m[j]=(1ll*m[j]+lucas(n,n/i,j))%p[j];
}
}
}
printf("%d\n",fp(G,CRT(),mod));
}