[hdu2855][矩阵乘法]Fibonacci Check-up

Fibonacci Check-up

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

Problem Description
Every ALPC has his own alpc-number just like alpc12, alpc55, alpc62 etc.
As more and more fresh man join us. How to number them? And how to avoid their alpc-number conflicted?
Of course, we can number them one by one, but that’s too bored! So ALPCs use another method called Fibonacci Check-up in spite of collision.

First you should multiply all digit of your studying number to get a number n (maybe huge).
Then use Fibonacci Check-up!
Fibonacci sequence is well-known to everyone. People define Fibonacci sequence as follows: F(0) = 0, F(1) = 1. F(n) = F(n-1) + F(n-2), n>=2. It’s easy for us to calculate F(n) mod m.
But in this method we make the problem has more challenge. We calculate the formula , is the combination number. The answer mod m (the total number of alpc team members) is just your alpc-number.

Input
First line is the testcase T.
Following T lines, each line is two integers n, m ( 0<= n <= 10^9, 1 <= m <= 30000 )

Output
Output the alpc-number.

Sample Input
2
1 30000
2 30000

Sample Output
1
3

Source
2009 Multi-University Training Contest 5 - Host by NUDT

sol:

求解C(n,0)*f(0)+C(n,1)*f(1)……C(n,n)*f(n)
打表发现可以递推,g[i]=g[i-1]*3+g[i-2]
标算做法:
考虑二项式定理,(a+b)^n=C(n,0)*a^n+C(n,1)*a^n-1*b+…..+C(n,n)*b^n
和上面要求的式子非常相似,如果a是1,b^i表示f(i)的话,这个式子就和上面完全等价了。就相当于求矩阵(1+b)^n。其中1是单位矩阵。b是fib的转移矩阵,因为b^n代表的也就是f(n)
那么(1+b)^n= iC(n,i)bi1ni ∑ i C ( n , i ) ∗ b i ∗ 1 n − i
接下来从矩阵的角度解释下数学上是不是对的
考虑矩阵满足结合律,分配律,显然矩阵的二项式是成立的。先把单位矩阵乘完,再乘b^i,显然这个东西就是b^i,然后C(n,i)*b^i的话,就相当于把整个矩阵的树都乘上了C(n,i),比如我们f(n)存在b[1,1]里面,那么你的答案就在c[1,1],其中c=(1+b)^n,最后外面的那层 就相当于是把这些乘完C(n,i)的fib矩阵给累加了起来。

方法二

#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef long long ll;
typedef double s64;
int n,m;
inline int read()
{
    char c;
    int res,flag=0;
    while((c=getchar())>'9'||c<'0') if(c=='-')flag=1;
    res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=(res<<3)+(res<<1)+c-'0';
    return flag?-res:res;
}
const int N=3;
int a[N][N],b[N][N],tmp[N][N],pyz;
inline void simplex(int a[N][N])
{
    memset(tmp,0,sizeof(tmp));
    for(int i=1;i<=2;++i)
    for(int j=1;j<=2;++j)
    for(int k=1;k<=2;++k)
    tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j]%pyz)%pyz;
    for(int i=1;i<=2;++i)
    for(int j=1;j<=2;++j)
    a[i][j]=tmp[i][j];
}
inline int ksm(int t)
{
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    a[1][2]=1;
    b[1][1]=1;
    b[1][2]=1;
    b[2][1]=1;
    b[2][2]=2;
    while(t)
    {
        if(t&1) simplex(a);
        simplex(b);
        t>>=1;
    }
    return a[1][1];
}
inline void solve()
{
    n=read();
    pyz=read();
    printf("%d\n",ksm(n));
}
int main()
{
//  freopen("2855.in","r",stdin);
//  freopen(".out","w",stdout);
    int T=read();
    while(T--) solve();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值