#pragma GCC optimize ( "O3" ) #pragma GCC target ( "avx" ) #include #include #include #include #include using namespace std; using ll = long long; #define TYPE_OF( VAR ) remove_const::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 FOREQINV( VAR , INITIAL , FINAL ) for( TYPE_OF( INITIAL ) 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 POWER_MOD( ANSWER , ARGUMENT , EXPONENT , MODULO ) \ TYPE_OF( ARGUMENT ) ANSWER{ 1 }; \ { \ TYPE_OF( ARGUMENT ) ARGUMENT_FOR_SQUARE_FOR_POWER = ( MODULO + ( ARGUMENT ) % MODULO ) % MODULO; \ 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; \ } \ } \ // POWER_MODを使う #define FACTORIAL_MOD( ANSWER , ANSWER_INV , MAX_I , LENGTH , MODULO ) \ static ll ANSWER[LENGTH]; \ static ll ANSWER_INV[LENGTH]; \ { \ ll VARIABLE_FOR_PRODUCT_FOR_FACTORIAL = 1; \ ANSWER[0] = VARIABLE_FOR_PRODUCT_FOR_FACTORIAL; \ FOREQ( i , 1 , MAX_I ){ \ ANSWER[i] = ( VARIABLE_FOR_PRODUCT_FOR_FACTORIAL *= i ) %= MODULO; \ } \ POWER_MOD( FACTORIAL_MAX_INV , ANSWER[MAX_I] , MODULO - 2 , MODULO ); \ ANSWER_INV[MAX_I] = FACTORIAL_MAX_INV; \ FOREQINV( i , MAX_I - 1 , 0 ){ \ ANSWER_INV[i] = ( FACTORIAL_MAX_INV *= i + 1 ) %= MODULO; \ } \ } \ \ template INT GCD( const INT& b_0 , const INT& b_1 ) { INT b[2] = { b_0 , b_1 }; int i_0 = ( b_0 >= b_1 ? 0 : 1 ); int i_1 = 1 - i_0; while( b[i_1] != 0 ){ b[i_0] %= b[i_1]; swap( i_0 , i_1 ); } return b[i_0]; } int main() { UNTIE; CEXPR( int , bound_T , 256 ); CIN_ASSERT( T , 1 , bound_T ); CEXPR( ll , bound_HW , 100000 ); CEXPR( ll , P , 998244353 ); FACTORIAL_MOD( factorial , factorial_inv , bound_HW , bound_HW + 1 , P ); ll answer, gcd , sum , r , j , j_rest; REPEAT( T ){ CIN_ASSERT( H , 4 , bound_HW ); CIN_ASSERT( W , 4 , bound_HW ); answer = H * W; gcd = GCD( H , W ); if( gcd > 3 ){ answer += gcd * 2; if( gcd > 4 ){ if( ( ( H * W ) / gcd ) % 3 == 0 ){ answer += gcd * 12; } } if( gcd % 2 == 0 ){ FOR( i , 0 , 2 ){ sum = 0; r = ( gcd + i * 3 ) % 6; j = r == 0 ? 6 : r; // 解説の分類およびパターン5をあまり理解していません。。 // とりあえず結果を鵜呑みにしています。すみません。 while( ( j_rest = ( gcd / 2 - j * 5 ) / 3 ) >= 0 ){ sum += ( factorial[ j - 1 + j_rest ] * ( ( factorial_inv[j] * factorial_inv[j_rest] ) % P ) ) % P; j += 6; } ( ( sum %= P ) *= gcd ) %= P; answer += sum * sum; } if( gcd % 4 == 0 ){ answer += 16; } } } COUT( answer % P ); } QUIT; }