Cod sursa(job #2264126)

Utilizator k.bruenDan Cojocaru k.bruen Data 19 octombrie 2018 20:18:59
Problema Al k-lea termen Fibonacci Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.8 kb
#include <iostream>
#include <vector>
#include <cassert>
#include <fstream>

using std::vector;
using std::cout;


uint64_t mul_mod(uint64_t a, uint64_t b, uint64_t m)
{
    uint64_t d = 0, mp2 = m >> 1;
    int i;
    if (a >= m) a %= m;
    if (b >= m) b %= m;
    for (i = 0; i < 64; ++i)
    {
        d = (d > mp2) ? (d << 1) - m : d << 1;
        if (a & 0x8000000000000000ULL)
            d += b;
        if (d >= m) d -= m;
        a <<= 1;
    }
    return d;
}


class Matrix
{
private:
	vector< vector<int> > A;
	unsigned int rows, columns;
public:
	Matrix(unsigned int size) {
		A = vector< vector<int> >(size, vector<int>(size, 0));
		rows = columns = size;
	}
	Matrix(unsigned int r, unsigned int c) {
		A = vector< vector<int> >(r, vector<int>(c, 0));
		rows = r;
		columns = c;
	}
	Matrix(vector< vector<int> > x) {
		A = x;
		rows = x.size();
		columns = x[0].size();
	}

	const unsigned int getRows() {
		return rows;
	}
	const unsigned int getColumns() {
		return columns;
	}

	vector<int>& operator[](int x) {
		return A[x];
	}

	Matrix operator=(Matrix other) {
		rows = other.rows;
		columns = other.columns;

		A = other.A;

		return *this;
	}

	Matrix operator=(vector< vector<int> > vec) {
		A = vec;
		
		rows = vec.size();
		columns = vec[0].size();

		return *this;
	}

	const Matrix operator+(Matrix other) {
		Matrix aux(rows, columns);
		
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < columns; j++) {
				aux[i][j] = A[i][j] + other[i][j];
			}
		}

		return aux;		
	}

	const Matrix operator-(Matrix other) {
		Matrix aux(rows, columns);
		
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < columns; j++) {
				aux[i][j] = A[i][j] - other[i][j];
			}
		}
		
		return aux;
	}				


	const Matrix operator*(Matrix other) {
		assert(columns == other.rows);

		int n = rows, m = other.columns;

		Matrix aux(n, m);

		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				int sum = 0;
				
				for (int k = 0; k < columns; k++) {
					sum += A[i][k] * other[k][j];
				}
				aux[i][j] = sum;
			}
		}

		return aux;
	}

	const Matrix multiply_with_modulo(Matrix other, int modulo) {
		assert(columns == other.rows);

		int n = rows, m = other.columns;

		Matrix aux(n, m);

		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				int sum = 0;
				
				for (int k = 0; k < columns; k++) {
                    sum += mul_mod(A[i][k], other[k][j], modulo);
				}
				aux[i][j] = sum;
			}
		}

		return aux;
	}

	// ( 1 2 9 8 )   ( 1 2 3 )
	// ( 5 2 5 2 )   ( 3 2 1 )
	// ( 7 9 1 1 ) * ( 7 3 4 ) = ?
	// ( 2 2 2 2 )   ( 9 1 2 )
	// ( 1 5 4 3 )   

	// Concluzie: 5|4 * 4|3 = 5|3

	// ( 142 41 67 ) (1*1+2*3+9*7+8*9 1*2+2*2+9*3+8*1 1*3+2*1+9*4+8*2)
	// (  64 31 41 )
	// (  )
	// (  )
	// (  )

	const Matrix operator/(Matrix other) {
		std::cerr << "YOU MORON!" << '\n';
		assert(false); // You dun goofed!
	}
};

template<typename T>
T raise_to_power(T init, int power) {
	if (power == 1) return init;

	if (power % 2 != 0) return init * raise_to_power(init, power - 1);
	
	T rez = init * init;
	return raise_to_power(rez, power / 2);
}

template<typename T>
T raise_to_power_modulo(T init, int power, int modulo = 666013) {
	if (power == 1) return init;

	if (power % 2 != 0) return init * raise_to_power(init, power - 1);
	
	T rez = init.multiply_with_modulo(init, modulo);
	return raise_to_power(rez, power / 2);
}

std::ifstream fin("kfib.in");
std::ofstream fout("kfib.out");

int main() {

	int k;
	fin >> k;
	Matrix Z = { { {0,1},{1,1} } };

	Matrix M1 = {{{0, 1}}};

	//Matrix Mk = M1 * raise_to_power_modulo(Z, k - 1, 666013);
	Matrix Mk = M1 * raise_to_power(Z, k - 1);

	fout << Mk[0][1] << '\n';
	return 0;
}