[HDU](6395)Sequence ---- 矩阵快速幂+分块

题目链接

做法:一开始推出了和正确题解一样的基础矩阵,可是自己想的太局限,没有想到分块的思想。还是缺乏练习呀!

具体做法,就是我们先把一部分的用O(1)的递推式计算好,然后后面的按照每相同的p/n 进行分块,然后这样就不会错了。

 参考题解:https://www.cnblogs.com/DynastySun/p/9470717.html

#include<bits/stdc++.h>
#define rep(i,s,t) for(int i = (int)(s); i <= (int)(t); i++)
#define rev(i,t,s) for(int i = (int)(t); i >= (int)(s); i--)
#define pb(x) push_back(x)
#define all(x) x.begin(),x.end()
#define sz(x) (int)(x).size()
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
const double PI = 4*atan(1.0);
const int maxn = 5e5+5;
const int INF = 0x3f3f3f3f;
ll A,B,C,D,P,N;
int f[maxn];
struct mat{
    ll a[15][15];
    mat(){
        memset(a,0,sizeof(a));
    }
};
mat mul(mat x,mat y)
{
    mat res;
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
            for(int k=0;k<3;k++)
                res.a[i][j] = (res.a[i][j]+x.a[i][k]*y.a[k][j])%mod;
    return res;
}
ll qpow(ll fn_1, ll fn_2, ll c, ll b)
{
    mat res;
    for(int i=0;i<3;i++)
        res.a[i][i] = 1;
    mat bas;
    bas.a[0][0] = D;bas.a[0][1] = C;bas.a[0][2] = 1;
    bas.a[1][0] = 1;bas.a[1][1] = 0;bas.a[1][2] = 0;
    bas.a[2][0] = 0;bas.a[2][1] = 0;bas.a[2][2] = 1;
    while(b)
    {
        if(1&b) res = mul(res,bas);
        bas = mul(bas,bas);
        b>>=1;
    }
    ll ans = (res.a[0][0]*fn_1%mod+res.a[0][1]*fn_2%mod+res.a[0][2]*c%mod)%mod;
    return ans;
}
void Init()
{
    f[1] = A;
    f[2] = B;
    for(int i=3;i<maxn;i++)
        f[i] = (C*f[i-2]%mod+D*f[i-1]%mod+(P/i))%mod;
}
int main()
{
    #ifdef LOCAL_FILE
    freopen("in.txt","r",stdin);
    #endif // LOCAL_FILE
    ios_base::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        ll ans = 0;
        cin>>A>>B>>C>>D>>P>>N;
        Init();
        if(N<maxn)
            cout<<f[N]<<endl;
        else
        {
            ll m = maxn;
            ll a = f[m-1];
            ll b = f[m-2];
            ll c = P/m;
            ll num;
            if(c!=0)//从第m项开始分块计算
            {
                num = P/c-m+1;//计算出P/m = c的有多少项
                while(m+num-1<N)//计算出f[m]~f[n]项
                {
                    ll tfn_,tfn_1;
                    tfn_ = qpow(a,b,c,num);//算出中间的fm,num个相同的[p/m]
                    tfn_1 = qpow(a,b,c,num-1);
                    m+=num;
                    a = tfn_;//更新f[m-1]
                    b = tfn_1;//更新f[m-2]
                    c = P/m;
                    if(c == 0) break;//c = 0 说明后面的c都为0了,剩下的直接用快速幂
                    num = P/c-m+1;
                }
            }
            num = N-m+1;
            ans = qpow(a,b,c,num);
            cout<<ans<<endl;
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值