急速な倍増
参照コード
pair<int, int> fib(int n) {
if (n == 0) return {
0, 1};
auto p = fib(n >> 1);
int c = p.first * (2 * p.second - p.first);
int d = p.first * p.first + p.second * p.second;
if (n & 1)
return {
d, c + d};
else
return {
c, d};
}
コードは記事のソースです:https://oi-wiki.org/math/fibonacci/
モジュール的な意味での周期性
トピック
7-13ログスタッキング(25分)
大興安嶺は多くの木材を生産しています。列車に積み込む前に、木材ジャッキは最初に2ログの高さ以内のどこかにログを配置します。横から見ると、ログスタックの図は次のとおりです。
各レイヤーのログの数は、少なくとも1つのログについて下位レイヤーよりも少なく、各レイヤーのログは1行で接続されていることがわかっています。
上の図では、スタックの最下層に4つのログがあり、スタックの最上層に3つのログがあります。つまり、写真は7つのログが一緒に蓄積された1種類の図を示しています。
さて、ログの総数を考えると、リトルジャイロは可能な数字がいくつあるか知りたいと思っています。
入力仕様:
複数のテストケースがあります。入力の最初の行は整数T(1≤T≤10含有
5を
テストケースの数を示します)。各テストケースについて:
各行には、ログの総数を示す1つの整数n(1≤n≤2×10
9
)が含まれています。
出力仕様:
入力のテストケースごとに、対応する数の可能な数値を出力する必要があります。
数値が非常に大きい可能性があるため、mod10000という数値を出力するだけです。
サンプル入力:
5
1
3
5
7
2000000000
サンプル出力:
1
2
5
13
3125
ヒント:
3番目のサンプルでは、次の方法で5つのログを蓄積できます。
まず、5つの丸太すべてを1階に置くことができます。
次に、最下層に4つのログを配置でき、最後のログを積み上げるための3つの位置があります。
その後、最下層に3つのログを配置し、他の2つのログを最上層に配置することもできます。
とりわけ、5つのログを蓄積するために1 + 3 + 1 = 5の数字を得ることができます。
問題解決
上記のプロパティを使用して漸化式を一覧表示し、テーブルを入力してルールを見つけます。期間Tは75000です。
コード
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
const int maxn = 1e4 + 2;
const int p = 10000;
int Fib[p];
// 奇数 F(2k + 1) = F(k + 1) ^ 2 + F(k) ^ 2;
// 偶数 F(2k) = F(k)(2F(k + 1) - F(k));
// 该题周期性, 周期为75000
int fib(int n) {
// if (n == 2 || n == 1) return 1;
if (n < maxn) return Fib[n];
int a = fib(n / 2) % p; // F(k)
int b = fib(n / 2 + 1) % p; // F(k + 1)
if (n & 1) {
//为奇数
return (a * a % p + b * b % p) % p;
} else {
//为偶数
return a * (2 * b - a + p) % p;
}
}
int main() {
Fib[1] = 1;
for (int i = 2; i < maxn; i++) {
Fib[i] = (Fib[i - 1] + Fib[i - 2]) % p;
}
int T, n;
cin >> T;
while (T--) {
scanf("%d", &n);
cout << fib(n % 75000) << endl;
}
system("pause");
return 0;
}