HDU6395:Sequence(矩阵快速幂)

Let us define a sequence as below 

⎧⎩⎨⎪⎪⎪⎪⎪⎪F1F2Fn===ABC⋅Fn−2+D⋅Fn−1+⌊Pn⌋{F1=AF2=BFn=C⋅Fn−2+D⋅Fn−1+⌊Pn⌋



  Your job is simple, for each task, you should output FnFn module 109+7109+7. 

Input

The first line has only one integer TT, indicates the number of tasks. 

Then, for the next TT lines, each line consists of 66 integers, AA , BB, CC, DD, PP, nn.

1≤T≤200≤A,B,C,D≤1091≤P,n≤1091≤T≤200≤A,B,C,D≤1091≤P,n≤109 

Output

36
24

Sample Input

2
3 3 2 1 3 5
3 2 2 2 1 4

Sample Output

36
24

 

题意:算出给定的递推式,留意到下取整对于一段连续区间的值都一样,那么分段处理即可,分段数为根号n级别,那么套矩阵快速幂就是O(sqrt(n) * log(n))。

 # include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod = 1e9+7;
struct Mat{LL mat[3][3];};
int T;
LL a,b,c,d,p,n;
Mat k;
Mat operator *(Mat a, Mat b)
{
    Mat c;
    for(int i=0; i<3; ++i)
        for(int j=0; j<3; ++j)
        {
            c.mat[i][j] = 0;
            for(int k=0; k<3; ++k)
            {
                c.mat[i][j] += a.mat[i][k]*b.mat[k][j]%mod;
                c.mat[i][j] %= mod;
            }
        }
    return c;
}

Mat operator ^(Mat a, int b)
{
    Mat c;
    for(int i=0; i<3; ++i)
        for(int j=0; j<3; ++j)
        c.mat[i][j] = (i==j);
    for(;b;b>>=1)
    {
        if(b&1) c = c*a;
        a = a*a;
    }
    return c;
}
void solve(int n, int x)
{
    k.mat[0][2] = 1LL*x;
    Mat p;
    for(int i=0; i<3; ++i)
        for(int j=0; j<3; ++j)
            p.mat[i][j] = 0;
    p.mat[0][0] = d;
    p.mat[1][0] = c;
    p.mat[2][0] = p.mat[0][1] = p.mat[2][2] = 1LL;
    p = p^n;
    k = k*p;
}
 int main()
 {
     for(scanf("%d",&T);T;--T)
     {
         for(int i=0; i<3; ++i)
             for(int j=0; j<3; ++j)
                 k.mat[i][j] = 0;
         LL ans = 0;
         scanf("%lld%lld%lld%lld%lld%lld",&a,&b,&c,&d,&p,&n);
         if(n == 1) {printf("%lld\n",a);continue;}
         else if(n == 2) {printf("%lld\n",b);continue;}
         k.mat[0][0] = b;
         k.mat[0][1] = a;
         for(int i=3,j; i<=min(p,n); i=j+1)
         {
             j=p/(p/i);
             j = min(j, (int)n);
             solve(j-i+1, p/i);
         }
         if(n > max(p,2*1LL)) solve(n-max(p,2*1LL), 0);
         printf("%lld\n",k.mat[0][0]);
     }
     return 0;
 }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值