hdu 6395 Sequence (整除分块+矩阵快速幂)

本文介绍了一种使用矩阵快速幂优化斐波那契数列计算的方法,并结合整除分块技巧来进一步减少计算复杂度。通过预处理和动态更新的方式,在接近O(√nlogn)的时间复杂度内求解特定形式的斐波那契数列问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在原始斐波那契数列上,第i项要加上 p/i
整除分块,复杂度根号nlogn(事实上不是,但是差不多这样)

#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#include <cstring>
#define debug(x) //std::cerr << #x << " = " << (x) << std::endl
using namespace std;
typedef long long LL;
const int MAXN = 5e6 + 17;
const LL MOD = 1e9+7;
struct matrix{
    static const int MATRIX_N = 5;
    LL a[MATRIX_N][MATRIX_N];
    int row, col;
    matrix():row(MATRIX_N),col(MATRIX_N){memset(a,0,sizeof(a));}
    matrix(int x, int y):row(x),col(y){memset(a,0,sizeof(a));}
    LL* operator [] (int x){return a[x];}
    matrix operator * (matrix x){
        matrix tmp(row, x.col);
        for(int i = 0; i < row; i++)
            for(int j = 0; j < col; j++) if(a[i][j])
                for(int k = 0; k < x.col; k++) if (x[j][k]){
                    tmp[i][k] = (tmp[i][k]+(a[i][j] * x[j][k])%MOD)%MOD;
                    tmp[i][k] %= MOD;
                }
        return tmp;
    }
    void operator *= (matrix x){*this = *this * x;}

    matrix operator ^ (LL x){
        matrix ret(row, col);
        for (int i = 0; i < col; i++) ret[i][i] = 1;
        matrix tmp = *this;
        for (; x; x >>= 1, tmp *= tmp){if (x&1) ret *= tmp;}
        return ret;
    }
    void print(){
        for (int i = 0; i < row; i++){
            for (int j = 0; j < col; j++) printf("%lld ",a[i][j]);
            puts("");
        }
        puts("");
    }
};
int dap[MAXN];
int main()
{
#ifdef noob
    freopen("Input.txt", "r", stdin);
    freopen("Output.txt", "w", stdout);
#endif
    int t;
    cin>>t;
    while(t--)
    {
        LL a,b,c,d,p,n,q = 1;
        scanf("%lld%lld%lld%lld%lld%lld",&a,&b,&c,&d,&p,&n);
        dap[0] = 2;
        LL x = 0;
        for(LL l=1,r;l<=n;l=r+1)
        {
            if(l>p)
            {
                dap[q++] = n;
                break;
            }
            r=p/(p/l);
            if(r>2)
                dap[q++] = r;
        }
        LL fir = b,sec = a,zt,sz = q-1;
        matrix ori(3,3);
        ori[0][0] = d,ori[0][1] = c,ori[0][2] = 1;
        ori[1][0] = 1,ori[1][1] = 0,ori[1][2] = 0;
        ori[2][0] = 0,ori[2][1] = 0,ori[2][2] = 1;
        matrix son(3,1);
        for (LL r=0; r <= n;++x)
        {
            r = dap[x];
            if(r>=n) break;
            LL dis = n-r;
            if(x<sz-1)
                dis = min(dap[x+1]-r,dis);
            if(dis<0) break;
            zt = p/(r+dis);
            son[0][0] = fir,son[1][0] = sec,son[2][0]=zt;
            // son.print();
            ori[0][0] = d,ori[0][1] = c,ori[0][2] = 1;
            ori[1][0] = 1,ori[1][1] = 0,ori[1][2] = 0;
            ori[2][0] = 0,ori[2][1] = 0,ori[2][2] = 1;
            ori = ori^dis;
            son = ori*son;
            // ori.print();
            // son.print();
            fir = son[0][0];
            sec = son[1][0];
        }
        printf("%lld\n",fir );
        // cout<<fir<<endl;
    }
    return 0;    
}

很不应该,整除分块几乎一瞬间就想到了,但是不知为何又否认了,应该是我对这个只有一个听过名字的印象,太糟糕了.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值