2019牛客暑期多校训练营(第五场)——B(矩阵快速幂)

问题虫洞——B:generator 1

 

黑洞内窥:

输入两行,一行x0, x1, a, b,    一行n,mod。

给出一个序列的x0,x1,之后的每一项由公式: 得出,a, b也已知,,,,

求F(n)%mod;

but,,,,

你的数据非常大。。。

 

思维光年:

一开始是模仿斐波那契递推公式来的,但是那个公式有限制条件,,

后来想到了矩阵快速幂,也推出了矩阵乘方,但n太™大了,,,

后来想了想,好像你先幂一个数然后再幂一个数,其实是等于幂了这两个数的积,

比赛的时候以为是幂了这两个数的和,所以一直没敢敲。。。。怕爆。。。

而正确的题解是:

2019牛客暑期多校训练营(第五场)——B(矩阵快速幂)_第1张图片

 

ACcode:

//#include
//std::ios::sync_with_stdio(false);
#include  
#include 
#include
#include      
#include      
#include    
#include    
#include   
#include   
#include   
#include  
#include 
#include 
using namespace std;
typedef long long ll;
#define MAXN 1000005
#define INF 0x3f3f3f3f//将近ll类型最大数的一半,而且乘2不会爆ll
//const ll mod = 998244353;
#define mem(a, b) memset(a, b, sizeof(a))

char n[MAXN];
ll mod, a, b, x0, x1;

struct mat
{
    ll m[4][4];
};

mat mul(mat a, mat b)
{
    mat res;
    for(int i=0; i<4; ++i)
        for(int j=0; j<4; ++j)
            res.m[i][j] = 0;
    for(int i=1; i<=2; ++i)
        for(int j=1; j<=2; ++j)
            for(int k=1; k<=2; ++k)
                res.m[i][k] = (res.m[i][k] + a.m[i][j]*b.m[j][k])%mod;
    return res;
}

mat pow(mat a, int b)
{
    mat ans;
    memset(ans.m, 0, sizeof(ans.m));
    ans.m[1][1] = ans.m[2][2] = 1;
    while(b)
    {
        if(b&1)
            ans = mul(ans, a);
        a = mul(a, a);
        b >>= 1;
    }
    return ans;
}

int main()
{
    scanf("%lld %lld %lld %lld %s %lld", &x0, &x1, &a, &b, n, &mod);
    int len = strlen(n);
    mat ans, ori;
    mem(ans.m, 0); mem(ori.m, 0);
    ori.m[1][2] = 1, ori.m[2][1] = b, ori.m[2][2] = a;
    ans.m[1][1] = 1, ans.m[2][2] = 1;
    for(int i = len-1; i>=0; --i)    //重点,以10为单位。
    {
        mat t = pow(ori, n[i]-'0');
        ans = mul(ans, t);
        ori = pow(ori, 10);
    }
    cout << (x0*ans.m[1][1]+x1*ans.m[1][2])%mod << '\n';
    return 0;
}

 

 

你可能感兴趣的:(一九暑测)