HDU 6395 Sequence 矩阵快速幂+分块

Let us define a sequence as below


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≤200≤A,B,C,D≤1091≤P,n≤109

Sample Input

2

3 3 2 1 3 5

3 2 2 2 1 4

Sample Output

36

24

题意:求Fn

思路:n很大,显然要使用矩阵快速幂,观察有P/n向下取整,所以可以利用分块+快速幂来计算

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <cmath>
using namespace std;

#define Matr 4
typedef long long ll;
const int mmax = 1e5 + 5;
const ll mod = 1e9 + 7;
int num[mmax];

struct mat//矩阵结构体,a表示内容,size大小 矩阵从1开始
{
    ll a[Matr][Matr],size;
    mat()
    {
        size=0;
        memset(a,0,sizeof(a));
    }
};
void print(mat m)//输出矩阵信息,debug用
{
    int i,j;
    printf("%d\n",m.size);
    for(i=0;i<m.size;i++)
    {
        for(j=0;j<m.size;j++)printf("%d ",m.a[i][j]);
        printf("\n");
    }
}

mat multi(mat m1,mat m2)//两个相等矩阵的乘法,对于稀疏矩阵,有0处不用运算的优化
{
    mat ans=mat();    ans.size=m1.size;
    for(int i=1;i<=m1.size;i++)
        for(int j=1;j<=m2.size;j++)
            if(m1.a[i][j])//稀疏矩阵优化
                for(int k=1;k<=m1.size;k++)
                    ans.a[i][k]=(ans.a[i][k]+m1.a[i][j]*m2.a[j][k])%mod;

    return ans;
}
mat quickmulti(mat m,mat re,int n)//二分快速幂
{
    mat ans=mat();
    int i;
    for(i=1;i<=m.size;i++)
        for(int j=1;j<=3;j++)
          ans.a[i][j]=re.a[i][j];
    ans.size=m.size;
    while(n)
    {
        if(n&1)ans=multi(m,ans);
        m=multi(m,m);
        n>>=1;
    }
    return ans;
}

int main()
{
    int A,b,c,d,p,n,t;
    scanf("%d",&t);
    while(t--){
      scanf("%d%d%d%d%d%d",&A,&b,&c,&d,&p,&n);
      mat re,k;
      k.a[1][1]=d; k.a[1][2]=c; k.a[1][3]=p;
      k.a[2][1]=1; k.a[2][2]=0; k.a[2][3]=0;
      k.a[3][1]=0; k.a[3][2]=0; k.a[3][3]=1;
       for (int i=1;i<=3;i++)
            re.a[i][i]=1;
        re.size=3; k.size=3;
      int mid1=0,mid2,len=0;
      for(int i=1;i<=p;i++){   //刚开始都出现一次,出现相同即停止
         mid2=p/i;
         if(mid1==mid2)
            break;
         num[len++]=mid2;
         mid1=mid2;
      }
      for(int i=mid2-1;i>0;i--)
            num[len++]=i;
        num[len]=0;
        while(num[len-1]<3)
            len--;
        num[len]=2;
        int i;
        for(i=len-1;i>=0;i--)
        {
           if(n<num[i]) break;
           k.a[1][3]=p/num[i];
               re=quickmulti(k,re,num[i]-num[i+1]);
        }
        k.a[1][3]=p/n;
        re=quickmulti(k,re,n-num[i+1]);
        int sum=(re.a[1][1]*b+re.a[1][2]*A+re.a[1][3])%mod;
        printf("%d\n",sum);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/deepseazbw/article/details/81635561
今日推荐