版权声明: https://blog.csdn.net/moon_sky1999/article/details/88022333
题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=6185
思路来自:https://blog.csdn.net/elbadaernu/article/details/77825979
对于每个f[i],大致可以分成5种情况进行转移。推导式子的过程如下:
/*
1.
1000
1000
2000
2000
f[i-1]
2.
1000
1000
2200
3300
f[i-2]+f[i-3]+...+f[1]
3.
1100
2200
3300
4400
f[i-2]
4.
1100
2200
3000
3000
f[i-2]+f[i-3]+...+f[1]
5.
1100
2000
2000
3300
f[i-2]+f[i-4]+...+f[2/1]
(1)f[i]=f[i-1]+f[i-2]+2*(f[i-2]+f[i-3]+...+f[1])+(f[i-2]+f[i-4]+...+f[2/1])
带入i-2
(2)f[i-2]=f[i-3]+f[i-4]+2*(f[i-4]+...+f[1])+(f[i-4]+...+f[2/1])
两式左右相减
f[i]-f[i-2]=f[i-1]+f[i-2]-f[i-3]-f[i-4]+2*(f[i-2]+f[i-3])+f[i-2]
化简可得:
f[i]=f[i-1]+5*f[i-2]+f[i-3]-f[i-4]
*/
构造矩阵
1 5 1 -1
1 0 0 0
0 1 0 0
0 0 1 0
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define ll long long
#define ull unsigned long long
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
const ll mod = 1e9 + 7;
using namespace std;
int m = 4;
struct matrix {
ll num[5][5];
matrix() { memset(num, 0, sizeof num); }
matrix operator*(const matrix &x) {
matrix c;
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= m; ++j) {
for (int k = 1; k <= m; ++k) {
c.num[i][j] = (c.num[i][j] + num[i][k] * x.num[k][j] + mod) % mod;
}
}
}
return c;
}
matrix &operator=(const matrix &x) {
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= m; ++j) {
num[i][j] = x.num[i][j];
}
}
return *this;
}
};
matrix pow_mod(matrix &x, ll k) {
matrix ans;
for (int i = 1; i <= m; ++i) {
ans.num[i][i] = 1;
}
while (k) {
if (k & 1)ans = ans * x;
x = x * x;
k >>= 1;
}
return ans;
}
int main() {
ll n;
ll f[5];
f[1] = 36;
f[2] = 11;
f[3] = 5;
f[4] = 1;
while (~scanf("%lld", &n)) {
matrix a;
a.num[1][1] = 1;
a.num[1][2] = 5;
a.num[1][3] = 1;
a.num[1][4] = -1;
a.num[2][1] = 1;
a.num[3][2] = 1;
a.num[4][3] = 1;
if (n <= 4) {
printf("%lld\n", f[4 - n + 1]);
continue;
}
matrix b = pow_mod(a, n - 4);
ll ans = 0;
for (int i = 1; i <= 4; ++i) {
ans += b.num[1][i] * f[i];
ans += mod;
ans %= mod;
}
printf("%lld\n", ans);
}
return 0;
}