HDU 6395 Sequence(分块矩阵快速幂)

Sequence

Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 1585 Accepted Submission(s): 568

Problem Description
Let us define a sequence as below

{ F 1 = A F 2 = B F n = C F n 2 + D F n 1 + p n

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

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

Then, for the next T lines, each line consists of 6 integers, A , B, C, D, P, n.

1 T 20
0 A , B , C , D 10 9
1 P , n 10 9

Sample Input
2
3 3 2 1 3 5
3 2 2 2 1 4

Sample Output
36
24

思路

如果没有 P n 就是一个简单的快速幂,但是现在有了这个,那么我们会发现 P i ,在 P 固定的时候 P i 的值是分段的,例如我们让P为30,下面是不同的i所对应的 P i 的值

[ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 , 10 ] [ 11 , 15 ] [ 16 , 30 ] 30 15 10 7 6 5 4 3 2 1

因为在每个区间内 P i 的值是固定的所以我们可以构造出快速幂的公式
( F n F n 1 P n ) = ( D C 1 1 0 0 0 0 1 ) ( F n 1 F n 2 P n ) = ( D C 1 1 0 0 0 0 1 ) n i ( F i F i 1 P n )

那现在是如何找出每段 P i 的开始和结尾,通过观察式子我们会发现每次的每个区间的末项就是 P P i P P i + 1 就是下一项的开始,这个分段的思想在很多莫比乌斯反演的题目中常用来优化,既然有了每一段的首项和末项,我们每次记录一下每一段区间开始前的前两项用来求得这一段最后一个数,然后再来判断一下, P P i m i n ( n , p ) 哪个小即可,当i大于p的时候 P i 为0,那就是一个二维的矩阵快速幂了, 3 x 3 矩阵中 2 x 2 的部分直接拿来用就可以了

扫描二维码关注公众号,回复: 2854356 查看本文章
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#define MAX 3
using namespace std;
typedef struct {
long long m[MAX][MAX];
}Matrix;
Matrix P;
Matrix I={1,0,0,0,1,0,0,0,1};
const long long mod=1e9+7;
Matrix Matrixmul(Matrix a,Matrix b)
{
    int i,j,k;
    Matrix c;
    for(i=0;i<MAX;i++)
        for(j=0;j<MAX;j++)
        {
            c.m[i][j]=0;
            for(k=0;k<MAX;k++)
            {
                c.m[i][j]+=(a.m[i][k]*b.m[k][j])%mod;
            }
            c.m[i][j]%=mod;
        }
        return c;
}
Matrix quickpow(long long n)
{
    Matrix m=P,b=I;
    while(n>0)
    {
        if(n%2==1)
            b=Matrixmul(b,m);
        n=n/2;
        m=Matrixmul(m,m);
    }
    return b;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(P.m,0,sizeof(P.m));
        int a,b,c,d,n,p;
        scanf("%d%d%d%d%d%d",&a,&b,&c,&d,&p,&n);
        if(n==2)
        {
            printf("%d\n",a);
            continue;
        }
        else if(n==1)
        {
            printf("%d\n",b);
            continue;
        }
        P.m[0][0]=d%mod;
        P.m[0][1]=c%mod;
        P.m[0][2]=1;
        P.m[1][0]=1;
        P.m[2][2]=1;
        long long ans=0;
        long long ta=a%mod;
        long long tb=b%mod;
        int m=min(n,p);
        for(int i=3,last;i<=m;i=last+1)
        {
            last=min(p/(p/i),m);
            Matrix A=quickpow(last-i+1);
            ans=(A.m[0][0]*tb%mod+A.m[0][1]*ta%mod+A.m[0][2]*(p/i)%mod+mod)%mod;
            ta=(A.m[1][0]*tb%mod+A.m[1][1]*ta%mod+A.m[1][2]*(p/i)%mod+mod)%mod;
            tb=ans;
        }
        if(n>p)
        {
            Matrix A=quickpow(n-max(p,2));
            ans=(A.m[0][0]*tb%mod+A.m[0][1]*ta%mod+mod)%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ftx456789/article/details/81673592
今日推荐