题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4291
思路:如果直接利用n做三次矩阵快速幂求解是不对的。因为三次快速幂对1000000007取模,会超精度。所以必须本地处理寻找每层的循环节,最外层最1000000007取模,则找到最外层的循环节是222222224,次外层对222222224取模,找到次外层循环节是183120。接下来利用这三个不同的mod进行三层快速幂。
暴力查找你循环节代码:
/**
*
* █████▒█ ██ ▄████▄ ██ ▄█▀ ██████╗ ██╗ ██╗ ██████╗
* ▓██ ▒ ██ ▓██▒▒██▀ ▀█ ██▄█▒ ██╔══██╗██║ ██║██╔════╝
* ▒████ ░▓██ ▒██░▒▓█ ▄ ▓███▄░ ██████╔╝██║ ██║██║ ███╗
* ░▓█▒ ░▓▓█ ░██░▒▓▓▄ ▄██▒▓██ █▄ ██╔══██╗██║ ██║██║ ██║
* ░▒█░ ▒▒█████▓ ▒ ▓███▀ ░▒██▒ █▄ ██████╔╝╚██████╔╝╚██████╔╝
* ▒ ░ ░▒▓▒ ▒ ▒ ░ ░▒ ▒ ░▒ ▒▒ ▓▒ ╚═════╝ ╚═════╝ ╚═════╝
* ░ ░░▒░ ░ ░ ░ ▒ ░ ░▒ ▒░
* ░ ░ ░░░ ░ ░ ░ ░ ░░ ░
* ░ ░ ░ ░ ░
**/
#include<bits/stdc++.h>
using namespace std;
#define debug(x) cerr<<#x<<'='<<(x)<<endl;
#define debugp(x) cerr<<#x<<"= {"<<(x.first)<<", "<<(x.second)<<"}"<<endl;
#define debug2(x, y) cerr<<"{"<<#x<<", "<<#y<<"} = {"<<(x)<<", "<<(y)<<"}"<<endl;
#define ll long long
const int maxn = 2e5 + 7;
const int mod = 1e9 + 7;
int main()
{
ll a = 0, b = 1;
for(ll i = 1; ; i++)
{
a = (3 * b + a) % mod;
swap(a, b);
if(a == 0 && b == 1)
{
cout << i <<endl;
break;
}
}
}
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 2;
ll n, k;
int MOD;
struct Matrix
{
ll m[MAXN][MAXN];
void init(int x)
{
memset(m, 0, sizeof(m));
for(int i = 0; i < MAXN; i++){
m[i][i] = x;
}
}
Matrix operator * (const Matrix &a) const
{
Matrix res;
res.init(0);
for(int i = 0; i < MAXN; i++)
for(int j = 0; j < MAXN; j++)
for(int k = 0; k < MAXN; k++)
res.m[i][j] = (res.m[i][j] + (m[i][k] * a.m[k][j]) % MOD) % MOD;
return res;
}
};
Matrix quickPow(Matrix x, ll p)
{
Matrix res;
res.init(1);
x = x * res;
while(p)
{
if(p & 1) res = res * x;
p >>= 1;
x = x * x;
}
return res;
}
Matrix a, x;
void init()
{
a.init(0);
a.m[0][0] = 3; a.m[0][1] = 1;
a.m[1][0] = 1; a.m[1][1] = 0;
x.init(0);
x.m[0][0] = 1;
x.m[1][0] = 0;
}
ll solve(ll n)
{
init();
return (quickPow(a, n) * x).m[1][0];
}
int main()
{
while(~scanf("%lld",&k))
{
MOD = 183120;
k = solve(k);
MOD = 222222224;
k = solve(k);
MOD = 1000000007;
k = solve(k);
printf("%lld\n",k);
}
return 0;
}