[템플릿] A * B 문제 업그레이드 된 버전 (고속 푸리에 변환 FFT)

제목 설명

$ $ N 자리의 십진수 X와 Y를 X의 * y를 찾을 두 감안할 때 (참조 루오 밸리 P1919를 )

분석

가정 FFT / NTT를 배웠습니다.

$ X = 10 $에 해당하는 특별한 경우 정밀 곱셈을 제외하고 다항식 곱셈.

예를 들어, N = 111 (123)가 시크 * 3

$$ 123 = X ^ 2 + 3 + 2 × $$

$$ 111 = X ^ 2 + X + 1 $$

$$ \ 시작 {123} 배향 * 111 = (X ^ 2 + 3 + 2 ×) (X ^ 2 + X + 1) = \\ 및 X ^ 4 + 3X ^ 3 + (6X) ^ 2 + 3 + 5 배 \ \ = 13,653 및 단부 \ {} 배향 $$

코드 :

#INCLUDE <비트 / stdc ++ H.>
 #DEFINE의 RG 등록
 하여  스페이스 성병; 

타입 정의  LL;
CONST  INT 개조 = 998,244,353 , g = 3 ;
CONST의  INT maxn 6E4 + = 10 ; 

인라인 INT qpow ( INT (X), INT의 K) 
{ 
    INT ANS = 1 ;
    하면서 (K) 
    { 
        경우 (K & 1 ) 
            ANS = (LL)가 ans와 * X % 개조; 
        엑스= (LL) * X X %의 개조, K >> = 1 ; 
    } 
    반환 ANS; 
} 

인라인 INT의 모듈 ( INT의 X, INT의 Y) 
{ 
    X + = Y;
    만약 (x> = 개조) 
        X - = 개조;
    반환 X를; 
} 

INT의 브 [ 4 * maxn]; 
인라인 공극 NTT ( INT의 *를 t, INTINT 타입) 
{ 
     (RG의 INT에 I = 0 ; I <LIM; ++ I)
        경우 (전 < 레브 [I]) 
            스왑 (t [I], t [REV [I]); 
     (RG INT I = 1 ; I <LIM 나는 << = 1 ) 
    { 
        INT GN = qpow (g (mod- 1 ) / (I << 1 ));
        경우 (유형 == - 1 ) 
            GN = qpow (GN, mod- 2 );
         (RG INT J = 0 ; J <LIM] = J + (I << 1 )) 
        { 
            INT의 GI = 1 ;
             (RG의 INT를 K = 0, K <I; ++ K, GI = (LL) 위장관 *의 GN의 %의 개조) 
            { 
                INT (X) = t [J + K, Y = (LL) 위장관 *를 t [J + I + K] % 개조; 
                t [J + K = 모듈 (X, Y); 
                t [J I + K +] = 모듈 (X, mod- Y); 
            } 
        } 
    } 
    경우 (유형 == - 1 ) 
    { 
        INT INV = qpow (LIM, mod- 2 );
         (RG의 INT I = 0 ; I <LIM; ++ I) 
            t [I] = (LL) t [i]는 INV * % 개조; 
    } 
} 

INT X [ 4 * maxn], Y [ 4* MAXN] 
인라인 공극 MUL ( INT * X, INT * Y, INT N-, INT m) 
{ 
    memset 함수 (X-, 0 , sizeof의 (X-)) 
    가 memset합니다 (Y, 0 , sizeof의 합니다 (Y));
     INT 임 = . (1) , L = 0 ,   // 0 작성해야 = L은, 디폴트 값은 로컬 변수 않을 수도 0 
    그동안 (LIM <= N-m의 +) = 임 << 1. , L ++;    // 임보다 (N + m)의 (2)의 전력은 그 최대 4 배의 공간 
    을위한 ( int로 I = 0 ; I ++는, I는 림을 <) 계 [I] = (계 [I >> . 1] >> 1 ) | ((I & 1 ) << (L - 1 ));
     (RG INT I = 0 ; I <LIM; I ++) X [I]의 X = [I], Y [I] = Y [I]; 
    NTT (X, LIM, 1 ); 
    NTT (Y, LIM, 1 );
     (RG의 INT에 I = 0 ; I <LIM; I ++) X [I] = (LL) X [I] * Y [i]를 % 개조; 
    NTT (X, LIM, - 1 );
     (RG의 INT에 I = 0 ; I <LIM; I ++) × [I] =를 X [I]; 
} 


int로 N;
int로 A [ 4 * maxn, B의 [ 4* maxn];
문자 S [maxn]; 

INT 의 main () 
{ 
    는 scanf ( " %의 D ' , N); 
    scanf와 ( " %의 S ' , S);
    위한 ( int로 I = 0 A [I]가 S [N- 내가 ++; i가 N <) 1 - -i] ' 0 '을 ; 
    scanf와 ( " %의 S ' , S);
    위한 ( int로 I = 0 ; I <N은, 내가 ++) [I] =에서 S [N- B 1 -i] - ' 0 ' ; 
    MUL (A, B, N); 

//    경우 (나는 2 * N을 <; I = 0 int로 난 ++)에서 printf ( "%의 D"는 [I]);
//     의 printf ( "\ n")를; 

    INT의 TMP = 0 ;    // 进位을 
    위해 ( int로 난 = 0 ; i가 < 2 * N; 내가 ++)   //
     { 
        A [내가] = A [i]는 + TMP; 
        TMP가 = A [I] / 10 ; 
        A [I]는 A [i]는 (%) = 10 ; 

    } 

//     대해 (나는 2 * <N; I = 0 int로 난 ++)에서 printf ( "%의 D"는 [I]);
//     의 printf ( "\ n")를; 

    부울 플래그 = 진정한 ;
    대한 (INT I = 2 * N-; I는> = 0 , 난 -)   // 선두 제로 제거 차 역방향 출력 
    {
         IF (플래그 && A의이 [I]를 == 0 )   계속 ; 
         에서 printf ( " %의 D를 " , A [I] ) 
         플래그 = 거짓 ; 
    } 

    반환  0 ; 
}

 

추천

출처www.cnblogs.com/lfri/p/11242183.html