최대 10 전원 (18) : 목표는 n은 정말 엄청난 될 수있다, (m 최대 10 전원 5) F (n)의 모듈로 m을 계산하는 것이다.
내 알고리즘은 너무 느립니다.
내 방법 : 계산 및 반복 처리는 그 배열을 통해 다음, m까지의 모든 피보나치 수를 저장하고 피보나치의에 모듈을 적용 할 수 있습니다.
피사노 기간의 길이가 발견되면, 나는 어떤의 모듈을 계산하기 위해이 길이를 사용할 수 있습니다 F(n)
내 코드 :
import java.math.BigInteger;
import java.util.*;
public class FibonacciAgain {
private static ArrayList<BigInteger> calc_fib() {
ArrayList<BigInteger> fib = new ArrayList<>();
fib.add(BigInteger.ZERO);
fib.add(BigInteger.ONE);
for (int i = 2; i <= 100000; i++) {
fib.add(fib.get(i - 2).add(fib.get(i - 1)));
}
return fib;
}
private static long calculatePeriod(ArrayList<BigInteger> fib, long modulo) {
long periodLength = 0;
boolean periodFound = false;
long[] period = new long[1000000];
period[0] = 0;
period[1] = 1;
period[2] = 1;
int i = 3;
while (!periodFound) {
//period[i] = fib.get(i)
//period[i]= fib.get(i).divide(new BigInteger(String.valueOf(i))).longValue();
//System.out.println("Fib at " + i + ": " + fib.get(i));
period[i] = fib.get(i).mod(new BigInteger(String.valueOf(modulo))).longValue();
//System.out.println("1:" + period[i]);
//System.out.println("2:" + period[i - 1]);
// System.out.println("3: " + period[i - 2]);
if (i == 100000){
periodFound = true;
periodLength = i - 1;
}
// if (period[i] == 1 && period[i - 1] == 1 && period[i - 2] == 0) {
if (period[i - 1] == 1 && period[i - 2] == 0) {
periodFound = true;
periodLength = i - 2;
//System.out.println("found");
}
i++;
}
//System.out.println("Period Length:" + periodLength);
return periodLength;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
long n = scanner.nextLong();
long m = scanner.nextLong();
//M Fibonacci Numbers up to are stored here
ArrayList<BigInteger> fib = new ArrayList<>();
fib = calc_fib();
// get the length of the pisano period
long periodLength = calculatePeriod(fib, m);
//
long fibFirst = n%periodLength;
System.out.println(fib.get((int) fibFirst).mod(new BigInteger(String.valueOf(m))).longValue());
}
}
어떤 조언을 얼마나 빨리 만들려면?
사용할 필요가 없습니다 BigInteger
때문에이 :
1*2*3*4*...*N mod M
1+2+3+4+...+N mod M
와 같다
(...(((1*2 mod M)*3 mod M)*4 mod M)...*N mod M)
(...(((1+2 mod M)+3 mod M)+4 mod M)...+N mod M)
이는 많이 (가정 카라 츠바 승산) 발 빠르게해야 O(3*N*(n^log2(3)))
하고 또는 부가 O(N*n)
선형으로 도 훨씬 더 시간 상수와 multiplicants / 추가 항목의 비트 폭은 비례을 ...O(N)
n
IIRC가 빠른 fibonaci의 계산을위한 공식은 (변환 곳도 O(N)
근처 무언가로O(log(N))
다음은 몇 가지 예 : 빠른 피보나치 알고리즘
여기서 C ++ (순의 예 modfib0
를 빠르고) 및 ( modfib1
ALGO 2 × 2 행렬의 제곱 파워를 사용) :
//---------------------------------------------------------------------------
int modfib0(int n,int m)
{
for (int i=0,x0=0,x1=1;;)
{
if (i>=n) return x1; x0+=x1; x0%=m; i++;
if (i>=n) return x0; x1+=x0; x1%=m; i++;
}
}
//---------------------------------------------------------------------------
// matrix 2x2: 0 1
// 2 3
void modmul2x2(int *c,int *a,int *b,int m) // c[4] = a[4]*b[4] %m
{
int t[4];
t[0]=((a[0]*b[0])+(a[1]*b[2]))%m;
t[1]=((a[0]*b[1])+(a[1]*b[3]))%m;
t[2]=t[1]; // result is symetric so no need to compute: t[2]=((a[2]*b[0])+(a[3]*b[2]))%m;
t[3]=((a[2]*b[1])+(a[3]*b[3]))%m;
c[0]=t[0];
c[1]=t[1];
c[2]=t[2];
c[3]=t[3];
}
void modpow2x2(int *c,int *a,int n,int m) // c[4] = a[4]^n %m
{
int t[4];
t[0]=a[0]; c[0]=1;
t[1]=a[1]; c[1]=0;
t[2]=a[2]; c[2]=0;
t[3]=a[3]; c[3]=1;
for (;;)
{
if (int(n&1)!=0) modmul2x2(c,c,t,m);
n>>=1; if (!n) break;
modmul2x2(t,t,t,m);
}
}
int modfib1(int n,int m)
{
if (n<=0) return 0;
int a[4]={1,1,1,0};
modpow2x2(a,a,n,m);
return a[0];
}
//---------------------------------------------------------------------------
사용 된 제약 조건을 준수하기 위해 조심 int
변수가 있어야합니다 최소한 64 비트에서 폭 넓은! 나는 기존 32 비트 환경에서 그리고 난이 만 테스트 있도록 BIGINT 클래스 코드를 망치고 싶지 않았다 :
int x,m=30000,n=0x7FFFFFFF;
x=modfib0(n,m);
x=modfib1(n,m);
그리고 결과에 여기 :
[10725.614 ms] modfib0:17301 O(N)
[ 0.002 ms] modfib1:17301 O(log2(N))
당신이 빠른 너 한테 훨씬 빠르게 선형보다 많이 볼 수있는 것처럼 ... 그러나 측정 된 시간은 Windows 환경에 대한 너무 작 나는 그것도 충분히 빨리해야한다고 생각합니다 그래서 대부분의 시간은 오버 헤드 대신 함수 자체의 가능성이 높습니다 에 대한 n=10^18
복잡성 그대로 O(log2(N))
I 추정 :
64-31 = 33 bits
0.002 ms * 33 = 0.066 ms
64 비트 연산이 잘 아래 수행해야합니다 그래서 0.1 ms
내 컴퓨터에서 실행 시간의 I 생각 (AMD A8-5500 3.2 GHz의) 허용 ...
64 비트의 선형 너 한테은 다음과 같이 될 것이다 :
10.725614 s * 2^33 = 865226435999039488 s = 27.417*10^9 years
당신이 볼 수 있지만, 당신은 오래 전에 그 나이의 염색 것입니다 ...