계 승률을 소수로 계산하는 가장 효율적인 방법은 무엇입니까?


20

계수 후 계수를 효율적으로 계산하는 알고리즘을 알고 있습니까?

예를 들어 프로그래밍하고 싶습니다.

for(i=0; i<5; i++)
  sum += factorial(p-i) % p;

그러나 p계승을 직접 적용하기위한 큰 숫자 (프라임)입니다 (p108) .

파이썬에서는이 작업이 정말 쉽지만 최적화 방법을 알고 싶습니다.


6
문제가 당신이 윌슨의 정리를 사용하기를 원하는 것처럼 보입니다. 프라임 p , . 따라서 프로그래밍 언어를 사용하지 않고 답은 입니다. 문제를 일반화하고 싶습니까? 100(p1)!=1modp100
Aryabhata

5
문제를 더 명확하게 진술 할 수 있습니까? 계산 하시겠습니까 (X!) (mod (X+1)), 아니면 더 일반적인 (X!) (mod Y)가요? 그리고 이것이 factorial(100!)계승 함수를 두 번 적용하고 싶다는 의미는 아닙니다.
Keith Thompson

1
Wilson의 정리가 없었더라도 오버플로 문제를 피하는 데 도움 이되는 가 있습니다. (mn)modp=(mmodp)(nmodp)
Dave Clarke

8
윌슨 정리는 p 가 소수 일 때만 적용됩니다 . 귀하의 질문에 p 가 소수 라고 명시되어 있지 않으므로 작성한 내용이 올바르지 않습니다.
Dave Clarke

답변:


11

(이 답변은 처음에 질문 안에 asker jonaprieto 에 의해 게시되었습니다 .)

나는 윌슨의 정리를 기억 하고 작은 것들을 알아 차렸다.

위의 프로그램에서 다음을 쓰면 더 좋습니다 :

(p1)!1(modp)(p2)!(p1)!(p1)11(modp)(p3)!(p2)!(p2)1(p2)1(modp)(p4)!(p3)!(p3)1(p2)1(p3)1(modp) (p5)!(p4)!(p4)1(p2)1(p3)1(p4)1(modp)

그리고 당신은 찾을 수 때문에 , 그래서와 확장 된 유클리드 알고리즘 당신의 가치 찾을 수 있습니다 , 즉이다 역 계수.(pi)1gcd(p,pi)=1(pi)1

와 같이 동일한 합치를 볼 수도 있습니다 이므로 합은 그리고 처음에 계승을 인수 분해하면 를 얻게됩니다. 그리고 voila, 역 계수는 계승보다 더 효율적입니다.

(p5)!(p24)1(modp)(p4)!(p+6)1(modp)(p3)!(p2)1(modp)(p2)!1(modp)(p1)!1(modp)
(24)1+(6)1+(2)1
8(24)1(modp)

기본적으로 . 산뜻한! (pk)!(p+(k1)!(1)k)1(modp)
Thomas Ahle

죄송하지만 인수 분해 하면 다음과 같이 나타납니다.(24)1+61+(2)1
9(24)1=38

1

게시 한 예는 Euler problem # 381과 매우 밀접한 관련이 있습니다. 따라서 오일러 문제를 해결하지 못하는 답변을 게시하겠습니다. 나는 계 승률을 소수로 계산하는 방법을 게시 할 것입니다.

그래서 : n을 계산하는 방법! 모듈로 p?

빠른 관찰 : n ≥ p이면 n! 인수 p를 가지므로 결과는 0입니다. 매우 빠릅니다. 그리고 p가 소수 여야한다는 요구 사항을 무시하면 q는 p의 가장 작은 소수이며, n! n ≥ q 인 경우 모듈로 p는 0입니다. 또한 p가 귀하의 질문에 대답 할 수있는 주요한 이유는 아닙니다.

이제 당신의 예에서 (n-i)! 1 ≤ i ≤ 5가 나타났다. 5 개의 계승을 계산할 필요가 없습니다. (n-5)!를 계산하고, (n-4)를 곱하면 (n-4)가됩니다!, (n-3)을 곱하면 (n-3)이됩니다! 이것으로 작업이 거의 5 배 줄어 듭니다. 문제를 말 그대로 해결하지 마십시오.

문제는 n을 계산하는 방법입니다! 모듈로 m. 확실한 방법은 대략 n log n 소수 자릿수 인 n!을 계산하고 나머지 모듈로 p를 계산하는 것입니다. 힘든 일입니다. 질문 :이 결과를 어떻게 더 빨리 얻을 수 있습니까? 명백한 일을하지 않음으로써.

우리는 ((a * b * c) 모듈로 p = (((a * b) 모듈로 p) * c) 모듈로 p.

n!을 계산하려면 일반적으로 x = 1로 시작한 다음 x에 1, 2, 3, ... n을 곱합니다. 모듈로 공식을 사용하여 n을 계산합니다! x = 1로 시작하여 n!를 계산하지 않고 모듈로 p를 계산 한 다음 i = 1, 2, 3, .., n에 대해 x를 (x * i) 모듈로 p로 바꿉니다.

우리는 항상 x <p와 i <n을 가지고 있으므로, n *을 계산하는 데있어 더 높은 정밀도가 아니라 x * p를 계산하기에 충분한 정밀도 만 있으면됩니다. 그래서 n을 계산합니다! p ≥ 2의 모듈로 p는 다음 단계를 수행합니다.

Step 1: Find the smallest prime factor q of p. If n ≥ q then the result is 0.
Step 2: Let x = 1, then for 1 ≤ i ≤ n replace x with (x * i) modulo p, and x is the result. 

(일부 답변은 주어진 예제의 매우 특별한 경우에만 질문에 대답하고 윌러 문제 # 381을 해결하는 데 매우 유용하지만 일반적으로 묻는 질문을 해결하는 데는 유용하지 않은 Wilson의 정리를 언급합니다.)


-1

이것은 윌슨 정리의 구현 사용입니다.

factMOD 함수는 MOD-n이 n에 대해 거의 없을 때 계산 (n!) % MOD를 호출하는 함수입니다.

그렇지 않은 경우 다른 효율적인 접근 방법을 알고 있습니까 (예 : n = 1e6 및 MOD = 1e9 + 7)?

ll powmod(ll a, ll b){//a^b % MOD
  ll x=1,y=a;
  while(b){
    if(b&1){
      x*=y; if(x>=MOD)x%=MOD;
    }
    y*=y; if(y>=MOD)y%=MOD;
    b>>=1;
  }
  return x;
} 
ll InverseEuler(ll n){//modular inverse of n
  return powmod(n,MOD-2);
}
ll factMOD(ll n){ //n! % MOD efficient when MOD-n<n
   ll res=1,i;
   for(i=1; i<MOD-n; i++){
     res*=i;
     if(res>=MOD)res%=MOD;
   }
   res=InverseEuler(res);   
    if(!(n&1))
      res= -res +MOD;
  }
  return res%MOD;
}

1
코드는 실제로 주제가 아닙니다. 알고리즘에 대한 설명은 사람들이 코드를 작성하기로 결정한 언어를 이해하지 않아도되므로 실제 구현은 종종 이해하기 어려운 방식으로 최적화되기 때문에 훨씬 유용합니다. 답이 아닌 별도의 질문으로 질문하십시오. 스택 교환은 토론 게시판이 아닌 질문 및 답변 사이트이며 답변이 숨겨져 있는지 찾기가 어렵습니다. 감사!
David Richerby
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.