2017 Multi-University Training Contest - Team 2 Funny Function

Funny Function

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 642 Accepted Submission(s): 298

Problem Description
Function Fx,ysatisfies:
这里写图片描述

For given integers N and M,calculate Fm,1 modulo 1e9+7.

Input
There is one integer T in the first line.
The next T lines,each line includes two integers N and M .
1<=T<=10000,1<=N,M<2^63.

Output
For each given N and M,print the answer in a single line.

Sample Input
2
2 2
3 3

Sample Output
2
33

Source
2017 Multi-University Training Contest - Team 2
题目意思:就是根据一个公式求值,n,m较大。
设a[i] = a[i-1]+2*a[i-2]为x性质。
首先有一个规律就是,F(1,1) F(1,2)F(1,3) ,,,符合x性质。
F(2,1),F(2,2),F(2,3),,,也符合x性质。
证明的话,F(2,1) = F(1,1)+,,F(1,n),F(2,2) = F(1,2)+,,F(1,n+1),F(2,3) = F(1,3),,,+F(1,n+2);因为F(1,1),F(1,2),F(1,3)符合x性质,那么从上面那个式子可以发现,F(2,3)的每一个元素都可以用F(2,1)中的一个元素乘2加上F(2,2)的的一个元素组成,所以F(2,3) = F(2,1)*2+F(2,2);
根据斐波那契的性质,前n项和可以表示为k*a1+m*a2,那么,因为k,m可以用矩阵快速幂求出,求出k,m可以得到f(i,1),f(i,2)到f(i+1,1),f(i+1,2)的转移公式,再用一个矩阵快速幂就可以求出答案了。

#include <stdio.h>
#include <algorithm>
#include <math.h>
#include <vector>
#include <map>
#include <set>
#include <iostream>
#include <string.h>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int mod = 1e9 + 7;

//int mod;

void add(int &a,int b)
{
    a += b;
    if(a >= mod) a -= mod;
    //if(a >= mod) a -= mod;
}

struct matrix
{
    int e[4][4],n,m;
    matrix() {}
    matrix(int _n,int _m): n(_n),m(_m) {memset(e,0,sizeof(e));}
    matrix operator * (const matrix &temp)const
    {
        matrix ret = matrix(n,temp.m);
        for(int i=1;i<=ret.n;i++)
        {
            for(int j=1;j<=ret.m;j++)
            {
                for(int k=1;k<=m;k++)
                {
                    add(ret.e[i][j],1LL*e[i][k]*temp.e[k][j]%mod);
                }
            }
        }
        return ret;
    }
    matrix operator + (const matrix &temp)const
    {
        matrix ret = matrix(n,m);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                add(ret.e[i][j],(e[i][j]+temp.e[i][j])%mod);
            }
        }
        return ret;
    }
    void getE()
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                e[i][j] = i==j?1:0;
            }
        }
    }
};

matrix qpow(matrix temp,long long x)
{
    int sz = temp.n;
    matrix base = matrix(sz,sz);
    base.getE();
    while(x)
    {
        if(x & 1) base = base * temp;
        x >>= 1;
        temp = temp * temp;
    }
    return base;
}

void print(matrix p)
{
    int n = p.n;
    int m = p.m;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            printf("%d ",p.e[i][j]);
        }
        cout << endl;
    }
}



int main()
{
    int T;
    cin >> T;
    while(T--){
        long long n,m;
        scanf("%I64d %I64d",&n,&m);
        matrix a = matrix(3,3);
        matrix b = matrix(1,3);
        matrix ax = matrix(3,3);
        ax.e[1][1] = 1,ax.e[2][1] = 1;
        ax.e[2][2] = 1,ax.e[3][2] = 2;
        ax.e[2][3] = 1;
        a = ax;
        b.e[1][1] = 1,b.e[1][3] = 1;
        a = qpow(a,n-1);
        b = b*a;

        int k = b.e[1][1];
        b.e[1][1] =0,b.e[1][2] = 1, b.e[1][3] = 0;
        b = b*a;
        int mm = b.e[1][1];
        matrix aa = matrix(2,2);
        matrix bb = matrix(1,2);
        //cout << k << ' '<<mm << endl;
        aa.e[1][1] = k,aa.e[2][1] = mm;
        aa.e[1][2] = 2*mm%mod;aa.e[2][2] = (k+mm)%mod;
        bb.e[1][1] = 1,bb.e[1][2] = 1;
        //print(aa);
        aa = qpow(aa,m-1);
        bb = bb*aa;
        printf("%d\n",bb.e[1][1]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值