フィボナッチハーモニー(「HKUSTIFLYTEKカップ」第17回トンジ大学プログラムデザイン予選と大学ネットワークフレンドリーマッチJ、マトリックスファストパワー)

1.タイトルリンク:

フィボナッチ合計

2.トピックの主なアイデア:

物乞い  \ sum _ {i = 1} ^ {n} i ^ kfib(i)、\; \;  1 \ leq n \ leq 10 ^ {18}、1 \ leq k \ leq 100

3.分析:

ゲーム中、Du Jiao BMはwaを維持しましたが、ゲーム後、モジュラスが間違っていることがわかりました...

Dujiao BMは、テンプレートを直接配置して係数を変更することでACにできるため、ここではDujiao BM以外のソリューションのみを示します(Dujiao BMはそれを気に入らないのですか?

最初にシンボルの説明を行います

F_k(n)= \ sum _ {i = 1} ^ ni ^ kfib(i)

G_k(n)= \ sum _ {i = 1} ^ {n}(n-i)^ k fib(i)

 シンボル化後、タイトルが必要です F_k(n)

次に、F_k(n) 再帰式を見つけ ます

G_k(n)= \ sum_ {i = 1} ^ n(n-i)^ k fib(i)

G_k(n)= \ sum_ {i = 1} ^ n((-i)+ n)^ k fib(i)

G_k(n)= \ sum_ {i = 1} ^ n \ sum_ {j = 0} ^ k \ binom {k} {j}(-i)^ jn ^ {kj} fib(i)

G_k(n)= \ sum_ {i = 1} ^ n \ sum_ {j = 0} ^ k \ binom {k} {j}(-1)^ ji ^ jn ^ {kj} fib(i)

G_k(n)= \ sum_ {j = 0} ^ k \ binom {k} {j}(-1)^ jn ^ {kj} \ sum_ {i = 1} ^ ni ^ j fib(i)

G_k(n)= \ sum_ {j = 0} ^ k \ binom {k} {j}(-1)^ jn ^ {kj} F_j(n)

G_k(n)=(-1)^ kF_k(n)+ \ sum_ {j = 0} ^ {k-1} \ binom {k} {j}(-1)^ jn ^ {kj} F_j(n)

(-1)^ kF_k(n)= G_k(n)-\ sum_ {j = 0} ^ {k-1} \ binom {k} {j}(-1)^ jn ^ {kj} F_j(n)

計算するとき F_k(n) 、以前の F_j(n) 値が計算されているので、必要なのは ジン)、 \; \;  0 \ leq i \ leq k

次のG_k(n) 再帰式を求めています 

とき k = 0 の時間

G_0(n)= \ sum_ {i = 1} ^ {n} fib(i)= fib(i + 2)-1

とき k \ geq 1 の時間

G_k(n + 1)-G_k(n)= \ sum _ {i = 1} ^ {n + 1}(n + 1- i)^ kfib(i)-\ sum _ {i = 1} ^ {n }(n --i)^ kfib(i)

G_k(n + 1)-G_k(n)= \ sum _ {i = 1} ^ {n}(n + 1- i)^ kfib(i)-\ sum _ {i = 1} ^ {n}( n-i)^ kfib(i)

G_k(n + 1)-G_k(n)= \ sum _ {i = 1} ^ {n}((n + 1- i)^ k-(n-i)^ k)fib(i)

G_k(n + 1)-G_k(n)= \ sum _ {i = 1} ^ {n}(((n-i)+1)^ k-(n-i)^ k)fib(i)

G_k(n + 1)-G_k(n)= \ sum _ {i = 1} ^ {n}(\ sum_ {j = 0} ^ {k} \ binom {k} {j}(ni)^ j- (n-i)^ k)fib(i)

G_k(n + 1)-G_k(n)= \ sum _ {i = 1} ^ {n} \ sum_ {j = 0} ^ {k-1} \ binom {k} {j}(ni)^ jfib (私)

G_k(n + 1)-G_k(n)= \ sum_ {j = 0} ^ {k-1} \ binom {k} {j} \ sum _ {i = 1} ^ {n}(ni)^ jfib (私)

G_k(n + 1)-G_k(n)= \ sum_ {j = 0} ^ {k-1} \ binom {k} {j} G_j(n)

G_k(n + 1)= G_k(n)+ \ sum_ {j = 0} ^ {k-1} \ binom {k} {j} G_j(n)

G_k(n + 1)= \ sum_ {j = 0} ^ {k} \ binom {k} {j} G_j(n)

この時点で、マトリックスを使用してパワーをすばやく解決できます ジン)、 \; \;  0 \ leq i \ leq k

具体的には

 G = \ left [\ begin {matrix} G_k(n)&G_ {k-1}(n)&\ cdots&G_0(n)&fib(n + 2)&fib(n + 1)&1 \\ 0&0&\ cdots&0&0&0&0 \\ \ vdots&\ vdots&\ cdots&\ vdots&\ vdots&\ vdots&\ vdots \\ 0&0&\ cdots&0&0&0 &0 \ end {matrix} \ right] _ {k + 4}

G '= \ left [\ begin {matrix} G_k(n-1)&G_ {k-1}(n-1)&\ cdots&G_0(n-1)&fib(n + 1)&fib(n )&1 \\ 0&0&\ cdots&0&0&0&0 \\ \ vdots&\ vdots&\ cdots&\ vdots&\ vdots&\ vdots&\ vdots \\ 0&0&\ cdots& 0&0&0&0 \ end {matrix} \ right] _ {k + 4}

B = \ left [\ begin {matrix} \ binom {k} {k}&0&0&0&\ cdots&0&0&0&0&0 \\ \ binom {k} {k-1}& \ binom {k-1} {k-1}&0&0&\ cdots&0&0&0&0&0 \\ \ binom {k} {k-2}&\ binom {k-1} { k-2}&\ binom {k-2} {k-2}&0&\ cdots&0&0&0&0&0 \\ \ vdots&\ vdots&\ vdots&\ vdots&\ vdots&\ vdots &\ vdots&\ vdots&\ vdots&\ vdots \\ \ binom {k} {1}&\ binom {k-1} {1}&\ binom {k-2} {1}&\ binom {k- 3} {1}&\ cdots&\ binom {1} {1}&0&0&0&0 \\ \ binom {k} {0}&\ binom {k-1} {0}&\ binom { k-2} {0}&\ binom {k-3} {0}&\ cdots&\ binom {1} {0}&0&0&0&0 \\ 0&0&0&0&\ cdots &0&1&1&1&0 \\ 0&0&0&0&\ cdots&0&1&1&0&0 \\ 0&0&0&0&\ cdots&0&-1&0&0&1 \ end {matrix} \ right] _ {k + 4}

知っている G = G'B

A = \ left [\ begin {matrix} 0&0&\ cdots&1&2&1&1 \\ 0&0&\ cdots&0&0&0&0 \\ \ vdots&\ vdots&\ cdots &\ vdots&\ vdots&\ vdots&\ vdots \\ 0&0&\ cdots&0&0&0&0 \ end {matrix} \ right] _ {k + 4}

再帰計算は知っています G = AB ^ {n-1}

4.コードの実装:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int M = (int)1e2 + 4;
const ll mod = (ll)998244353;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;

ll n; int k;
ll g[M + 5];
ll f[M + 5];

struct node
{
    ll D[M + 5][M + 5];
};

ll quick(ll a, ll b)
{
    ll sum = 1;
    while(b)
    {
        if(b & 1) sum = sum * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return (sum + mod) % mod;
}

node mul(node a, node b)
{
    node c; memset(c.D, 0, sizeof(c.D));
    for(int i = 0; i < M; ++i)
    for(int j = 0; j < M; ++j)
    for(int l = 0; l < M; ++l)
    c.D[i][j] = (c.D[i][j] + a.D[i][l] * b.D[l][j] % mod) % mod;
    return c;
}

node quick(node a, ll b)
{
    node sum; memset(sum.D, 0, sizeof(sum.D));
    for(int i = 0; i < M; ++i) sum.D[i][i] = 1;
    while(b)
    {
        if(b & 1) sum = mul(sum, a);
        a = mul(a, a);
        b >>= 1;
    }
    return sum;
}

int main()
{
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
    scanf("%lld %d", &n, &k);
    node A, B;
    memset(A.D, 0, sizeof(A.D));
    memset(B.D, 0, sizeof(B.D));
    A.D[0][k] = 1, A.D[0][k + 1] = 2, A.D[0][k + 2] = 1, A.D[0][k + 3] = 1;
    for(int j = k; j >= 0; --j)
    {
        B.D[k][j] = 1;
        for(int i = k - 1; i >= j; --i) B.D[i][j] = (B.D[i][j + 1] + B.D[i + 1][j + 1]) % mod;
    }
    B.D[k][k] = 0;
    B.D[k + 1][k] = B.D[k + 1][k + 1] = B.D[k + 1][k + 2] = 1;
    B.D[k + 2][k] = B.D[k + 2][k + 1] = 1;
    B.D[k + 3][k] = -1, B.D[k + 3][k + 3] = 1;
    node G = mul(A, quick(B, n - 1));
    for(int i = 0; i <= k; ++i) g[i] = G.D[0][k - i];
    f[0] = G.D[0][k + 1] - 1;
    for(int i = 1; i <= k; ++i)
    {
        f[i] = g[i];
        for(int j = 0; j <= i - 1; ++j) f[i] = (f[i] + (((j&1)<<1)-1) * B.D[k - j][k - i] * quick(n % mod, i - j) % mod * f[j] % mod) % mod;
        if(i & 1) f[i] *= -1;
        f[i] = (f[i] + mod) % mod;
    }
    printf("%lld\n", f[k]);
    return 0;
}

 

おすすめ

転載: blog.csdn.net/The___Flash/article/details/106066577
おすすめ