bzoj3328 PYXFIB

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3328

【题解】

真心巧妙。

这个式子看起来不大好,稍作化简。

斐波那契数列第n项是斐波那契矩阵的n次方的左上角的数。

化成矩阵形式。

考虑二项式定理的矩阵形式。

就差一个[i mod k = 0]不对了,我们就需要构造一个式子,使得当i mod k = 0的时候该式子为1,否则为0.

考虑单位根,原根。

令g为原根,那么单位根w=g^((n-1)/k),且题目保证了k|n-1。

那么对于i属于[0,k-1],当且仅当i=0的时候,w^i=1。

那么构造

这个式子当i mod k=0的时候,w^i=k,否则为0.

进一步,除以一个k就能完成要求了。

然后我们将这个代入ans。

我们设B为答案矩阵,B[1,1]即为ans,那么

稍加转换

提前sigma,交换位置

那么我们构造

观察形式,那么答案就是

我们枚举k,然后快速幂计算F即可。

# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 5e5 + 10;

# define RG register
# define ST static

ll n;
int k, mod;
int g, w, inv, ans;

struct mat {
    int a, b, c, d;
    friend mat operator * (mat a, mat b) {
        mat c;
        c.a = (1ll * a.a * b.a + 1ll * a.b * b.c) % mod;
        c.b = (1ll * a.a * b.b + 1ll * a.b * b.d) % mod;
        c.c = (1ll * a.c * b.a + 1ll * a.d * b.c) % mod;
        c.d = (1ll * a.c * b.b + 1ll * a.d * b.d) % mod;
        return c;
    }
    friend mat operator ^(mat a, ll b) {
        mat ret = a; --b;
        while(b) {
            if(b&1) ret = ret * a;
            a = a * a; 
            b >>= 1;
        }
        return ret;
    }
}A;

inline int pwr(int a, ll b) {
    int ret = 1;
    while(b) {
        if(b&1) ret = 1ll * ret * a % mod;
        a = 1ll * a * a % mod;
        b >>= 1;
    }
    return ret;
}

int y[M], yn; 
inline int G() {
    yn = 0;
    int t = mod-1;
    for (int i=2; i*i<=t; ++i) {
        if(t%i == 0) {
            y[++yn] = i;
            if(i*i != t) y[++yn] = t/i;
        }
    }
    bool gg = 0;
    int g = 2;
    while(1) {
        gg = 0;
        for (int i=1; i<=yn; ++i)
            if(pwr(g, y[i]) == 1) {
                gg = 1;
                break;
            }
        if(!gg) return g; 
        ++g;
    }
}

inline int F(int x) {
    A.a = x+1, A.b = A.c = 1, A.d = x;
    A = A ^ n;
    x = pwr(x, mod-2);
    x = pwr(x, n);
    return 1ll * x * A.a % mod;
}

void sol() { 
    cin >> n >> k >> mod;
    
    g = G(); 
    w = pwr(g, (mod-1)/k);
    inv = pwr(w, mod-2);
    ans = 0;
//    cout << w << endl;
    
    for (int i=0, x=1; i<k; ++i, x = 1ll * x * inv % mod) {
        ans = ans + F(x);
        if(ans >= mod) ans -= mod;
    }
    
    ans = 1ll * ans * pwr(k, mod-2) % mod;
    ans = (ans + mod) % mod; 
    cout << ans << endl;
}

int main() {
    int T; cin >> T;
    while(T--) sol();
    return 0;
}
View Code

 

posted @ 2017-06-06 10:59  Galaxies  阅读(553)  评论(0编辑  收藏  举报