結果

問題 No.2993 冪乗乗 mod 冪乗
ユーザー 👑 p-adic
提出日時 2023-02-02 10:53:51
言語 C++17(gcc12)
(gcc 12.3.0 + boost 1.87.0)
結果
AC  
実行時間 359 ms / 10,000 ms
コード長 12,395 bytes
コンパイル時間 10,649 ms
コンパイル使用メモリ 282,940 KB
最終ジャッジ日時 2025-02-10 08:06:54
ジャッジサーバーID
(参考情報)
judge2 / judge1
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 32
権限があれば一括ダウンロードができます

ソースコード

diff #
プレゼンテーションモードにする

#pragma GCC optimize ( "O3" )
#pragma GCC optimize( "unroll-loops" )
#pragma GCC target ( "sse4.2,fma,avx2,popcnt,lzcnt,bmi2" )
#include <bits/stdc++.h>
using namespace std;
using uint = unsigned int;
using ll = long long;
#define MAIN main
#define TYPE_OF( VAR ) remove_const<remove_reference<decltype( VAR )>::type >::type
#define UNTIE ios_base::sync_with_stdio( false ); cin.tie( nullptr )
#define CEXPR( LL , BOUND , VALUE ) constexpr const LL BOUND = VALUE
#define CIN( LL , A ) LL A; cin >> A
#define ASSERT( A , MIN , MAX ) assert( ( MIN ) <= A && A <= ( MAX ) )
#define CIN_ASSERT( A , MIN , MAX ) CIN( TYPE_OF( MAX ) , A ); ASSERT( A , MIN , MAX )
#define FOR( VAR , INITIAL , FINAL_PLUS_ONE ) for( TYPE_OF( FINAL_PLUS_ONE ) VAR = INITIAL ; VAR < FINAL_PLUS_ONE ; VAR ++ )
#define FOREQ( VAR , INITIAL , FINAL ) for( TYPE_OF( FINAL ) VAR = INITIAL ; VAR <= FINAL ; VAR ++ )
#define REPEAT( HOW_MANY_TIMES ) FOR( VARIABLE_FOR_REPEAT , 0 , HOW_MANY_TIMES )
#define QUIT return 0
#define COUT( ANSWER ) cout << ( ANSWER ) << "\n";
#define RETURN( ANSWER ) COUT( ANSWER ); QUIT
template <typename INT1 , typename INT2> inline constexpr INT1& Residue( INT1& n , const INT2& M ) noexcept { return n < 0 ? ( ( ( ( ++n ) *= -1 ) %=
    M ) *= -1 ) += M - 1 : n %= M; }
template <typename INT1 , typename INT2> inline constexpr INT1 Residue( INT1&& n , const INT2& M ) noexcept { return move( Residue( n , M ) ); }
#define POWER( ANSWER , ARGUMENT , EXPONENT ) \
static_assert( ! is_same<TYPE_OF( ARGUMENT ),int>::value && ! is_same<TYPE_OF( ARGUMENT ),uint>::value ); \
TYPE_OF( ARGUMENT ) ANSWER{ 1 }; \
{ \
TYPE_OF( ARGUMENT ) ARGUMENT_FOR_SQUARE_FOR_POWER = ( ARGUMENT ); \
TYPE_OF( EXPONENT ) EXPONENT_FOR_SQUARE_FOR_POWER = ( EXPONENT ); \
while( EXPONENT_FOR_SQUARE_FOR_POWER != 0 ){ \
if( EXPONENT_FOR_SQUARE_FOR_POWER % 2 == 1 ){ \
ANSWER *= ARGUMENT_FOR_SQUARE_FOR_POWER; \
} \
ARGUMENT_FOR_SQUARE_FOR_POWER *= ARGUMENT_FOR_SQUARE_FOR_POWER; \
EXPONENT_FOR_SQUARE_FOR_POWER /= 2; \
} \
} \
#define POWER_MOD( ANSWER , ARGUMENT , EXPONENT , MODULO ) \
ll ANSWER{ 1 }; \
{ \
ll ARGUMENT_FOR_SQUARE_FOR_POWER = ( ( ARGUMENT ) % ( MODULO ) ) % ( MODULO ); \
ARGUMENT_FOR_SQUARE_FOR_POWER < 0 ? ARGUMENT_FOR_SQUARE_FOR_POWER += ( MODULO ) : ARGUMENT_FOR_SQUARE_FOR_POWER; \
TYPE_OF( EXPONENT ) EXPONENT_FOR_SQUARE_FOR_POWER = ( EXPONENT ); \
while( EXPONENT_FOR_SQUARE_FOR_POWER != 0 ){ \
if( EXPONENT_FOR_SQUARE_FOR_POWER % 2 == 1 ){ \
ANSWER = ( ANSWER * ARGUMENT_FOR_SQUARE_FOR_POWER ) % ( MODULO ); \
} \
ARGUMENT_FOR_SQUARE_FOR_POWER = ( ARGUMENT_FOR_SQUARE_FOR_POWER * ARGUMENT_FOR_SQUARE_FOR_POWER ) % ( MODULO ); \
EXPONENT_FOR_SQUARE_FOR_POWER /= 2; \
} \
} \
// 調-
#define BS( ANSWER , MINIMUM , MAXIMUM , EXPRESSION , TARGET ) \
ll ANSWER = MAXIMUM; \
{ \
ll VARIABLE_FOR_BINARY_SEARCH_L = MINIMUM; \
ll VARIABLE_FOR_BINARY_SEARCH_U = ANSWER; \
ll VARIABLE_FOR_DIFFERENCE_FOR_BINARY_SEARCH = ( TARGET ) - ( EXPRESSION ); \
if( VARIABLE_FOR_DIFFERENCE_FOR_BINARY_SEARCH == 0 ){ \
VARIABLE_FOR_BINARY_SEARCH_L = ANSWER; \
} else { \
ANSWER = ( VARIABLE_FOR_BINARY_SEARCH_L + VARIABLE_FOR_BINARY_SEARCH_U ) / 2; \
} \
while( VARIABLE_FOR_BINARY_SEARCH_L != ANSWER ){ \
VARIABLE_FOR_DIFFERENCE_FOR_BINARY_SEARCH = ( TARGET ) - ( EXPRESSION ); \
if( VARIABLE_FOR_DIFFERENCE_FOR_BINARY_SEARCH == 0 ){ \
break; \
} else { \
if( VARIABLE_FOR_DIFFERENCE_FOR_BINARY_SEARCH > 0 ){ \
VARIABLE_FOR_BINARY_SEARCH_L = ANSWER; \
} else { \
VARIABLE_FOR_BINARY_SEARCH_U = ANSWER; \
} \
ANSWER = ( VARIABLE_FOR_BINARY_SEARCH_L + VARIABLE_FOR_BINARY_SEARCH_U ) / 2; \
} \
} \
} \
template <typename INT , INT val_limit , int length_max>
class PrimeEnumeration
{
public:
INT m_val[length_max];
int m_length;
inline constexpr PrimeEnumeration();
};
template <typename INT , INT val_limit , int length_max>
inline constexpr PrimeEnumeration<INT,val_limit,length_max>::PrimeEnumeration() : m_val() , m_length( 0 )
{
bool is_comp[val_limit] = {};
for( INT i = 2 ; i < val_limit ; i++ ){
if( is_comp[i] == false ){
INT j = i;
while( ( j += i ) < val_limit ){
is_comp[j] = true;
}
m_val[m_length++] = i;
}
}
}
template <typename INT> inline int log( const ll& b , INT n )
{
int answer = -1;
while( n > 0 ){
n /= b;
answer++;
}
return answer;
}
template <typename INT>
INT ChineseRemainderTheorem( const INT& b_0 , const INT& c_0 , const INT& b_1 , const INT& c_1 , ll& lcm )
{
INT a[2][2];
INT b[2] = { b_0 , b_1 };
int i_0 = ( b_0 >= b_1 ? 0 : 1 );
int i_1 = 1 - i_0;
for( uint i = 0 ; i < 2 ; i++ ){
INT ( & ai )[2] = a[i];
for( uint j = 0 ; j < 2 ; j++ ){
ai[j] = ( i == j ? 1 : 0 );
}
}
INT q;
while( b[i_1] != 0 ){
INT& b_i_0 = b[i_0];
INT& b_i_1 = b[i_1];
INT ( &a_i_0 )[2] = a[i_0];
INT ( &a_i_1 )[2] = a[i_1];
q = b_i_0 / b_i_1;
a_i_0[i_0] -= q * a_i_1[i_0];
a_i_0[i_1] -= q * a_i_1[i_1];
b_i_0 %= b_i_1;
swap( i_0 , i_1 );
}
INT& gcd = b[i_0];
INT c = c_0 % gcd;
if( c_1 % gcd != c ){
return -1;
}
lcm = ( b_0 / gcd ) * b_1;
INT ( &a_i_0 )[2] = a[i_0];
INT& a_i_00 = a_i_0[0];
a_i_00 *= ( c_1 - c ) / gcd;
Residue( a_i_00 , lcm );
INT& a_i_01 = a_i_0[1];
a_i_01 *= ( c_0 - c ) / gcd;
a_i_01 = ( a_i_01 >= 0 ? a_i_01 % lcm : lcm - ( - a_i_01 - 1 ) % lcm - 1 );
return ( c + a_i_00 * b_0 + a_i_01 * b_1 ) % lcm;
}
void ComputeLocalAnswer( int& factor_num , vector<ll>& factor , vector<ll>& factor_power , vector<ll>& local_answer , bool& unsolvable , int& B ,
    const int& N , const ll& M , ll prime_curr )
{
int prime_curr_minus = prime_curr - 1;
int order = prime_curr_minus;
FOR( j , 0 , factor_num ){
const int& factor_j = factor[j];
while( order % factor_j == 0 ){
order /= factor_j;
}
}
order = prime_curr_minus / order;
factor_num++;
factor.push_back( prime_curr );
int exponent = 1;
B /= prime_curr;
while( B % prime_curr == 0 ){
exponent++;
B /= prime_curr;
}
exponent *= N;
POWER( factor_power_curr , prime_curr , exponent );
factor_power.push_back( factor_power_curr );
int valuation = 0;
int case_num;
ll M_shifted;
if( N == 0 ){
POWER_MOD( M_power , M , order , prime_curr );
M_shifted= Residue( 1 - M_power , prime_curr );
case_num = 0;
} else if( M == 1 ){
M_shifted = 0;
case_num = 0;
} else if( order == 1 ){
M_shifted = 1 - M;
while( M_shifted % prime_curr == 0 ){
M_shifted /= prime_curr;
valuation++;
}
Residue( M_shifted , factor_power_curr );
case_num = 1;
} else if( order == 2 ){
ll M_plus = 1 + M;
while( M_plus % prime_curr == 0 ){
M_plus /= prime_curr;
valuation++;
}
M_plus %= factor_power_curr;
M_shifted = 1 - M;
while( M_shifted % prime_curr == 0 ){
M_shifted /= prime_curr;
valuation++;
}
( Residue( M_shifted , factor_power_curr ) *= M_plus ) %= factor_power_curr;
case_num = 1;
} else if( prime_curr <= 11 ){
int extra = exponent << 1;
if( extra % prime_curr_minus == 0 ){
extra /= prime_curr_minus;
} else {
++( extra /= prime_curr_minus );
}
POWER( factor_power_extra , prime_curr , extra );
factor_power_extra *= factor_power_curr;
POWER_MOD( M_power , M , order , factor_power_extra );
M_shifted = 1 - M_power;
while( M_shifted % prime_curr == 0 && valuation < extra ){
M_shifted /= prime_curr;
valuation++;
}
Residue( M_shifted , factor_power_curr );
case_num = valuation < extra ? 1 : 2;
} else {
POWER_MOD( M_power , M , order , factor_power_curr );
M_shifted = Residue( 1 - M_power , factor_power_curr );
case_num = 2;
}
if( valuation == 0 && M_shifted % prime_curr != 0 ){
unsolvable = true;
return;
}
int Ki;
if( case_num == 0 ){
Ki = 0;
} else if( case_num == 1 ){
Ki = ( exponent / valuation ) + 1;
Ki += log( prime_curr , Ki );
} else {
Ki = exponent + 1;
Ki += log( prime_curr , Ki );
if( Ki >= prime_curr ){
Ki = prime_curr_minus;
}
}
local_answer.push_back( 0 );
ll& local_answer_curr = local_answer.back();
ll M_shifted_power = 1;
vector<ll> inverse{};
inverse.push_back( 0 );
inverse.push_back( 1 );
int inverse_size = 2;
FOREQ( k , 1 , Ki ){
int k_coprime = k;
int valuation_temp = valuation * k;
while( k_coprime % prime_curr == 0 ){
k_coprime /= prime_curr;
valuation_temp--;
}
k_coprime %= factor_power_curr;
while( k_coprime >= inverse_size ){
if( inverse_size % prime_curr == 0 ){
inverse.push_back( 0 );
} else {
// gcd( prime_curr , inverse_size ) == 1
// inverse_size != 1
// inverse_size_sub != 0
const ll inverse_size_sub = factor_power_curr % inverse_size;
const ll& inverse_size_sub_inv = inverse[inverse_size_sub];
if( inverse_size_sub_inv == 0 ){
// inverse_size_sub != 0
// inverse_size_sub_minus < inverse_size
const ll inverse_size_sub_minus = inverse_size - inverse_size_sub;
// gcd( prime_curr , inverse_size ) == 1
// inverse_size == inverse_size_sub + inverse_size_sub_minus
// gcd( prime_curr , inverse_size_sub ) != 1
// gcd( prime_curr , inverse_size_sub_minus ) == 1
const ll& inverse_size_sub_minus_inv = inverse[ inverse_size_sub_minus ];
inverse.push_back( ( inverse_size_sub_minus_inv * ( ( factor_power_curr / inverse_size ) + 1 ) ) % factor_power_curr );
} else {
inverse.push_back( factor_power_curr - ( ( inverse_size_sub_inv * ( factor_power_curr / inverse_size ) ) % factor_power_curr ) );
}
}
inverse_size++;
}
ll& k_coprime_inverse = inverse[k_coprime];
POWER_MOD( prime_curr_power , prime_curr , valuation_temp , factor_power_curr );
local_answer_curr += ( ( ( M_shifted_power *= M_shifted ) %= factor_power_curr ) * ( ( k_coprime_inverse * prime_curr_power ) % factor_power_curr
        ) ) % factor_power_curr;
}
if( order < inverse_size ){
( local_answer_curr *= inverse[order] ) %= factor_power_curr;
} else {
POWER_MOD( order_inverse , order , factor_power_curr - factor_power_curr / prime_curr - 1 , factor_power_curr );
( local_answer_curr *= order_inverse ) %= factor_power_curr;
}
( local_answer_curr *= -1 ) < 0 ? local_answer_curr += factor_power_curr : local_answer_curr;
return;
}
int MAIN()
{
UNTIE;
// 1000+1
CEXPR( int , prime_lim , 998 );
// 1000
CEXPR( int , length_max , 168 );
constexpr PrimeEnumeration<int,prime_lim,length_max> prime{};
CEXPR( int , bound_T , 100000 );
CIN_ASSERT( T , 1 , bound_T );
CEXPR( int , bound_B , 1000000 );
CEXPR( ll , bound_M , 1000000000000000000 );
REPEAT( T ){
CIN_ASSERT( B , 2 , bound_B );
CIN( int , N );
CIN_ASSERT( M , 0 , bound_M );
int factor_num = 0;
vector<ll> factor{};
vector<ll> factor_power{};
vector<ll> local_answer{};
bool unsolvable = false;
FOR( i , 0 , length_max ){
const int& prime_i = prime.m_val[i];
if( B % prime_i == 0 ){
ComputeLocalAnswer( factor_num , factor , factor_power , local_answer , unsolvable , B , N , M , prime_i );
} else if( B / prime_i < prime_i ){
break;
}
if( unsolvable ){
break;
}
}
if( B != 1 && ! unsolvable ){
int prime_last = B;
ComputeLocalAnswer( factor_num , factor , factor_power , local_answer , unsolvable , B , N , M , prime_last );
}
if( unsolvable ){
COUT( -1 );
} else {
ll base = 1;
ll answer = 0;
FOR( i , 0 , factor_num ){
ll lcm;
answer = ChineseRemainderTheorem( base , answer , factor_power[i] , local_answer[i] , lcm );
base = lcm;
}
COUT( answer );
}
}
QUIT;
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
0