第一眼看到认为十分莽
ZZ地认为需要挨着挨着算,还要用快速幂
不用分析题意了,Ans=2^(无穷)% p。
扩展欧拉定理:
a ^ ( b % ( p ) ) gcd ( a , p ) == 1 ( mod p ) ……………………1
a ^ b a ^b b < ( p ) ( mod p ) ……………………2
a ^ ( b % ( p ) + phi ( p ) ) gcd ( a , p ) != 1 , b >= ( p ) ( mod p ) ……………………3
本人不知道怎么证明!!!
根据欧拉定理:a ^ (p) 1 ( mod p )
那么其实可以对于式子1乘上a ^ phi (p),由于a ^ phi (p) 1 ( mod p ),所以相当于同余式子同时乘上了1,所以式子1可以划归为 a ^ b a ^ ( b % ( p ) + ( p ) ),又因为 inf 永远大于 ( p ) , 所以 3 式恒成立,所以不论 p 和 b 的关系如何,都可以表示:
a ^ b a ^ ( b % ( p ) + ( p ) )
所以,我们首先可以将题目的那个特别大的式子化简成一个较简单的式子:
2 ^ ( 2 ^ ( …… ) % ( p ) + ( p ) ) % p
接着我们又可以对 2 ^ ( 2 ^ ( …… ) % ( p ) + ( p ) ) % p 中 2 ^ ( …… ) 做同样的工作;
这样是不是可以递归处理了?
边界条件是:p == 1 时, ( p ) = 1 , 任意数 % 1 都是 0 ,所以 return 1 --- ( Inf % ( 1 ) = 0 , ( 1 ) = 1 ) 就好了!
AC 代码:
#include <bits/stdc++.h>
const int N = 1e7 + 10 ;
int phi [ N ] , prime [ N ] ;
int T ;
long long p ;
bool vis [ N ] ;
long long pow ( long long a , long long b , long long mod ) {
long long res = 1 ;
for ( ; b ; b >>= 1 , a = ( a * a ) % mod )
if ( b & 1 )
res = ( res * a ) % mod ;
return res % mod ;
}
long long dfs ( long long x ) {
if ( x == 1 ) return 1 ;
long long tmp = pow ( 2 , dfs ( 1ll * phi [ x ] ) , 1ll * phi [ x ] ) ;
return tmp + 1ll * phi [ x ] ;
}
int main ( ) {
phi [ 1 ] = 0 ;
vis [ 1 ] = true ;
for ( int i = 2 ; i <= 1e7 + 5 ; i ++ ) {
if ( ! vis [ i ] ) {
phi [ i ] = i - 1 ;
prime [ ++ prime [ 0 ] ] = i ;
}
for ( int j = 1 ; j <= prime [ 0 ] && prime [ j ] * i <= 1e7 + 5 ; j ++ ) {
vis [ prime [ j ] * i ] = true ;
if ( i % prime [ j ] == 0 ) {
phi [ i * prime [ j ] ] = phi [ i ] * prime [ j ] ;
break ;
}
else
phi [ i * prime [ j ] ] = phi [ i ] * ( prime [ j ] - 1 ) ;
}
}
scanf ( "%d" , & T ) ;
for ( int i = 1 ; i <= T ; i ++ ) {
scanf ( "%lld" , & p ) ;
printf ( "%lld\n" , pow ( 2 , dfs ( p ) , p ) ) ;
}
return 0 ;
}
其实不知道为什么,我在 BZOJ 和 洛谷 都 AC 了,但是有些同学 BZOJ 会 MLE,Emmm??