赛后题解——问题 G: 强(矩阵快速幂)

注释:能打表找规律的绝对不推导了,省时,深有体会!!!

问题 G: 强
题目描述

Lh:粉兔你教我一下抽屉原理吧
Clz:就是给你一个长度为 n 的序列,每个数只能取 0,1,2,那你连续取三个数必然有两个相等……
Lh:等等你梭啥,再说一遍
Clz:……emmm 当我没说
Marser:就是一个序列,对于每一个连续三元组都要满足其中至少有两个相等
现在粉兔问你:有多少个长度为 n 的序列满足粉兔的要求?请对 19260817 取模。

输入

一行一个正整数n(3≤n≤1018)。

输出

一行一个整数,含义如题。

样例输入

4

样例输出

51

提示

51 种序列如下:
[0,0,0,0],[0,0,0,1],[0,0,0,2],[0,0,1,0],[0,0,1,1],[0,0,2,0],[0,0,2,2],[0,1,0,0],[0,1,0,1],[0,1,1,0],[0,1,1,1],[0,1,1,2],[0,2,0,0],[0,2,0,2],[0,2,2,0],[0,2,2,1],[0,2,2,2],[1,0,0,0],[1,0,0,1],[1,0,0,2],[1,0,1,0],[1,0,1,1],[1,1,0,0],[1,1,0,1],[1,1,1,0],[1,1,1,1],[1,1,1,2],[1,1,2,1],[1,1,2,2],[1,2,1,1],[1,2,1,2],[1,2,2,0],[1,2,2,1],[1,2,2,2],[2,0,0,0],[2,0,0,1],[2,0,0,2],[2,0,2,0],[2,0,2,2],[2,1,1,0],[2,1,1,1],[2,1,1,2],[2,1,2,1],[2,1,2,2],[2,2,0,0],[2,2,0,2],[2,2,1,1],[2,2,1,2],[2,2,2,0],[2,2,2,1],[2,2,2,2]。

解决思路:直接暴力打表数学归纳法,然后矩阵快速幂加速。
上图!!!

结论: {   f ( 3 ) = 21   f ( 4 ) = 51   f ( n ) = 2 f ( n 1 ) + f ( n 2 ) \small \begin{cases} \ f(3)=21\\ \ f(4)=51\\ \ f(n)=2f(n-1)+f(n-2)\\ \end{cases}
构造矩阵:

//优化
#pragma GCC optimize(2)
//C
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
//C++
#include<unordered_map>
#include<algorithm>
#include<iostream>
#include<istream>
#include<iomanip>
#include<climits>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
//宏定义
#define N 1010
#define DoIdo main
//#define scanf scanf_s
#define it set<ll>::iterator
//定义+命名空间
typedef long long ll;
typedef unsigned long long ull;
const ll mod = 19260817;
const ll INF = 1e18;
const int maxn = 1e6 + 10;
using namespace std;
//全局变量
const int m = 2;
struct mat {
    ll m[3][3];
}ans;
//函数区
ll max(ll a, ll b) { return a > b ? a : b; }
ll min(ll a, ll b) { return a < b ? a : b; }
mat operator*(mat a, mat b) {
    mat res;
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= m; j++) {
            ll temp = 0;
            for (int k = 1; k <= m; k++) {
                temp = (temp + a.m[i][k] * b.m[k][j]) % mod;
            }
            res.m[i][j] = temp;
        }
    }
    return res;
}
void init() {
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= m; j++) {
            if (i == j) ans.m[i][j] = 1;
            else ans.m[i][j] = 0;
        }
    }
}
void quick_pow(mat a, ll b) {
    init();
    while (b) {
        if (b & 1) {
            ans = (ans * a);
        }
        a = (a * a);
        b >>= 1;
    }
}
//主函数
int DoIdo() {
 
    ios::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);
 
    ll n;
    cin >> n;
 
    mat A, B; A.m[1][1] = 21, A.m[1][2] = 51;
    B.m[1][1] = 0, B.m[1][2] = 1;
    B.m[2][1] = 1, B.m[2][2] = 2;
 
    if (n >= 5) quick_pow(B, n - 4);
 
 
    if (n == 3) cout << 21 << endl;
    else if (n == 4) cout << 51 << endl;
    else {
        ll ans1 = ((A.m[1][1] * ans.m[1][2]) % mod + (A.m[1][2] * ans.m[2][2]) % mod) % mod;
        cout << ans1 << endl;
    }
    return 0;
}
//分割线---------------------------------QWQ
/*
 
 
 
*/

猜你喜欢

转载自blog.csdn.net/qq_45739057/article/details/106278295