注释:能打表找规律的绝对不推导了,省时,身有体会!!!
问题 G: 强
题目描述
Lh:粉兔你教我一下抽屉原理吧
Clz:就是给你一个长度为 n \small n n的序列,每个数只能取 0 , 1 , 2 \small 0,1,2 0,1,2那你连续取三个数必然有两个相等……
Lh:等等你梭啥,再说一遍
Clz:……emmm 当我没说
Marser:就是一个序列,对于每一个连续三元组都要满足其中至少有两个相等
现在粉兔问你:有多少个长度为 n \small n n的序列满足粉兔的要求?请对19260817取模。
输入
一行一个正整数 n \small n n( 3 ≤ n ≤ 1 0 18 \small 3≤n≤10^{18} 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} ⎩⎨⎧ f(3)=21 f(4)=51 f(n)=2f(n−1)+f(n−2)
构造矩阵:
//优化
#pragma GCC optimize(2)
//C
#include
#include
#include
#include
//C++
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//宏定义
#define N 1010
#define DoIdo main
//#define scanf scanf_s
#define it set::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
/*
*/