DUToj1085 Water Problem(矩阵快速幂)

 

Problem I: Water Problem

Time Limit:3000/1000 MS (Java/Others)   Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:1405   Accepted:154

[Submit][Status][Discuss]

Description

函数 f:Z+→Zf:Z+→Z。已知 f(1),f(2)f(1),f(2) 的值,且对于任意 x>1x>1,有 f(x+1)=f(x)+f(x−1)+sin(πx2)f(x+1)=f(x)+f(x−1)+sin⁡(πx/2)。

求 f(n)f(n) 的值。

 

Input

多组数据。(数据组数 T≤100T≤100)

每组数据包含 33 个不超过 109109 的正整数,分别代表 f(1),f(2)f(1),f(2) 和 nn 的值。

Output

 输出 f(n)mod(109+7)f(n)mod(109+7)。每组输出末尾有换行符。

Sample Input

1 2 3
1 2 5

Sample Output

3
7

 

快速幂可以在o(logn)时间内求a^n%mod,求a^n%mod可以变为求a^(n/2)*a^(n%2)%mod 

 

矩阵快速幂也是用了类似的方法,把矩阵的n次幂变成n/2使其可在o(logn)的复杂度内求解。

 

f(x)和f(x+1)关系已知,又因为n有1e9的所以只能矩阵快速幂求解 设[f(2),f(1),1]为初始矩阵乘n次下面的矩阵后

[ 1,1,0] [ 1,1,0] [ 1,1,0] [ 1,1,0] 

[ 1,0,0] [ 1,0,0] [ 1,0,0] [ 1,0,0] 

[ 0,0,1] [-1,0,1] [ 0,0,1] [ 1,0,1] 

后变成[f(2+4*n),f(1+4*n),1]所以直接手算上面矩阵结果(手算比较快)

[ 5,  3,0] 

[ 3,  2,0] 

[-1,-1,1]

然后用矩阵快速幂求解,如所求f(x)中x不是2+4*n则求使2+4*n小于x的最大n。再用f(x+1)=f(x)+f(x-1)+sin(pi*x/2)求解即可

 

下面是代码:


#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

#define mod 1000000007

struct matrix

{

    ll m[3][3];

    matrix(){

        memset(this->m,0,sizeof(this->m));

    }

};

matrix r4;

matrix mul(matrix A,matrix B)

{

    matrix ret;

    for(int i=0;i<3;i++)

        for(int j=0;j<3;j++)

        {

            ret.m[i][j]=0;

            for(int k=0;k<3;k++)

                ret.m[i][j]+=A.m[i][k]*B.m[k][j]%mod;

        }

    return ret;

}

matrix pow(matrix A,long long n)

{

    matrix ret;

    ret.m[0][0]=1;ret.m[1][1]=1;ret.m[2][2]=1;

    while(n)

    {

        if(n&1)

            ret=mul(ret,A);

        A=mul(A,A);

        n>>=1;

    }

    return ret;

}

int main()

{

    long long si[5]={0,1,0,-1};

    int n;ll a,b,c,aans;long long ans2,ans1,tmp;

    r4.m[0][0]=5; r4.m[0][1]=3; r4.m[1][0]=3; r4.m[1][1]=2; r4.m[2][1]=-1; r4.m[2][0]=-1; r4.m[2][2]=1;

    while(scanf("%lld%lld%lld",&a,&b,&c)!=EOF)

    {

   if(c==1){

    printf("%lld\n",a);continue;

   }

   if(c==2){

    printf("%lld\n",b);continue;

   }

   if(c==3){

    printf("%lld\n",(a+b)%mod);continue;

   }

   if(c==4){

    printf("%lld\n",(b+a+b-1)%mod);continue;

   }   

    matrix ans;

    ans.m[0][0]=b;   ans.m[0][1]=a;   ans.m[0][2]=1;

    ans=mul(ans,pow(r4,(c-2)/4));

    ans2=ans.m[0][0]%mod;

    ans1=ans.m[0][1]%mod;

    for(int i=2+4*((c-2)/4);i<c;i++)

    {

            tmp=ans2;

            ans2+=ans1+si[i%4];

            ans2%=mod;

            ans1=tmp;

    }

    printf("%lld\n",((ans2%mod)+mod)%mod);

    }



    return 0;

}      

     

/**************************************************************

    Problem: 1085

    User: funer

    Language: C++

    Result: Accepted

    Time:0 ms

    Memory:1652 kb

****************************************************************/

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值