2019牛客多校训练 第五场 generator 1(矩阵快速幂,斐波那契)

2019牛客多校训练 第五场 generator 1(矩阵快速幂,斐波那契)

题目

https://ac.nowcoder.com/acm/contest/885/B

题意

第一行给你四个数x0,x1,a,b.
所有的x满足这样一个表达式:Xi = aXi-1 + bXi-2 (i>1)(与斐波那契相似)
第二行给你两个数n,mod.
n有106(只能当字符串存储),mod <= 2x109.
让你求Xn取mod的答案是多少。

题解

由于此题n的数据范围很大,而且又知道公式,所以可以很容易想到是矩阵快速幂的裸题,但由于n的范围很大,所以需将二进制的快速幂写法改为十进制。
公式如下:
在这里插入图片描述
注意:计算矩阵相乘的时候建议直接写成二维矩阵的大小,用for循环会TLE。

AC代码

#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
ll mod;
struct Mat{
    ll x[2][2];
    Mat(){};
    Mat(int a)
    {
        x[0][0]=1;
        x[1][1]=1;
        x[0][1]=0;
        x[1][0]=0;
    }
    void cls()
    {
        mem(x,0);
    }
    friend Mat operator *(const Mat &a,const Mat &b)
    {
        Mat c;
        c.cls();
//      for(int i=0;i<2;i++)//TLE
//      {
//          for(int j=0;j<2;j++)
//          {
//              for(int k=0;k<2;k++)
//              {
//                  c.x[i][j] += a.x[i][k]%mod * b.x[k][j]%mod;
//                  c.x[i][j] %= mod;
//              }
//          }
//      }
        ll tmp00=a.x[0][0]*b.x[0][0] % mod+a.x[0][1]*b.x[1][0] % mod;
        ll tmp01=a.x[0][0]*b.x[0][1] % mod+a.x[0][1]*b.x[1][1] % mod;
        ll tmp10=a.x[1][0]*b.x[0][0] % mod+a.x[1][1]*b.x[1][0] % mod;
        ll tmp11=a.x[1][0]*b.x[0][1] % mod+a.x[1][1]*b.x[1][1] % mod;
        c.x[0][0]=tmp00 % mod;
        c.x[0][1]=tmp01 % mod;
        c.x[1][0]=tmp10 % mod;
        c.x[1][1]=tmp11 % mod;
        return c;
    }
    friend Mat operator ^(Mat a,int n)
    {
        Mat ans = Mat(1);
        while(n)
        {
            if(n&1)
                ans = ans*a;
            a = a*a;
            n>>=1;
        }
        return ans;
    }
};
char n[1000005];
int main()
{
    ll x0,x1,a,b;
    scanf("%lld %lld %lld %lld",&x0,&x1,&a,&b);
    scanf("%s",n);
    scanf("%lld",&mod);
    int len = strlen(n);
    Mat ans = Mat(1);
    Mat base;
    base.x[0][0]=a;
    base.x[0][1]=b;
    base.x[1][0]=1;
    base.x[1][1]=0;
    if(len==1)
    {
        if(n[0]=='0')
        {
            printf("%lld\n",x0%mod);
            return 0;
        }
        else if(n[0]=='1')
        {
            printf("%lld\n",x1%mod);
            return 0;
        }  
    }
    int temp = len-1;
    while(1)// n-1
    {
        n[temp]--;
        if(n[temp]<'0')
        {
            n[temp]+=10;
            temp--;
        }
        else break;
    }
    for(int i=0;i<len;i++)
    {
        ans=ans^10;
        ans=ans*(base^(n[i]-'0'));
    }
    printf("%lld\n",(x1*ans.x[0][0]+x0*ans.x[0][1])%mod);
}
发布了51 篇原创文章 · 获赞 16 · 访问量 3367

猜你喜欢

转载自blog.csdn.net/weixin_43911945/article/details/98939350