hdu 4291矩阵快速幂
这题是去年成都网络赛的题,当时没做出来,杯具呀。
其实最关键的就是要懂得取余一定会循环的,如果能够找出循环节,就是一个巨大的突破。然后就是g(n)的求法,很显然硬求是不可能的,我们去年做这题的时候试图去找g(n)的通项公式,都找得差不多了,但实际上那毫无意义。因为我们是要找循环节,所以应该一层层地找。先看g(n) % 1000000007到哪里会循环。可以用矩阵的方法求g(n),暴力打出来,发现循环节是222222224。再来看g(g(n)) % 1000000007到哪里会循环。因为g(g(n)) % 1000000007对g(n)每隔222222224结果就会循环一次,所以g(g(n)) % 1000000007 = g(g(n) % 222222224) % 1000000007。所以g(n) % 222222224的循环节也就是g(g(n)) % 1000000007的循环节。暴力求出来是183120。最后再看g(g(g(n))) % 1000000007的循环节。同理g(n) % 183120的循环节就是g(g(g(n))) % 1000000007的循环节。暴力求出来是240。也就是说,最后的结果,n每隔240就会循环。所以最后的结果就是g(g(g(n % 240) % 183120) % 222222224) % 1000000007。用矩阵快速幂就可以过了。
我的暴力求循环节的代码如下:
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <ctime> #include <iostream> #include <algorithm> #include <queue> #include <set> #include <map> #include <stack> #include <string> #include <vector> #include <deque> #include <list> #include <functional> #include <numeric> #include <cctype> using namespace std; const int MAX_ORDER = 2; const int MOD = 1000000007; typedef long long typec; typedef struct MyMatrix { int row, col; typec num[MAX_ORDER][MAX_ORDER]; MyMatrix(int rr, int cc) { row = rr; col = cc; } inline void init() { memset(num, 0, sizeof(num)); } } MyMatrix; //矩阵乘法。注意:ma.col与mb.row一定要相等,否则会出问题 MyMatrix operator*(MyMatrix ma, MyMatrix mb) { int row = ma.row; int col = mb.col; int K = ma.col; MyMatrix numc(row, col); numc.init(); int i, j, k; for (i = 0; i < row; i++) { for (j = 0; j < col; j++) { for (k = 0; k < K; k++) { numc.num[i][j] += ma.num[i][k] * mb.num[k][j]; numc.num[i][j] %= MOD; } } } return numc; } //矩阵快速幂。注意:ma.col与ma.row一定要相等,否则会出问题 MyMatrix mpow(MyMatrix ma, int x) { int ord = ma.row; MyMatrix numc(ord, ord); numc.init(); for (int i = 0; i < ord; i++) { numc.num[i][i] = 1; } for (; x; x >>= 1) { if (x & 1) { numc = numc * ma; } ma = ma * ma; } return numc; } int main() { #ifndef ONLINE_JUDGE freopen("data.in", "r", stdin); #endif MyMatrix ori(1, 2); ori.num[0][0] = 0; ori.num[0][1] = 1; MyMatrix tran(2, 2); tran.num[0][0] = 0; tran.num[0][1] = 1; tran.num[1][0] = 1; tran.num[1][1] = 3; for(int t = 1; ; t++) { ori = ori * tran; if(ori.num[0][0] == 0 && ori.num[0][1] == 1) { printf("%d\n", t); break; } } return 0; }
最后通过的代码如下:
/* * hdu4291/win.cpp * Created on: 2012-11-4 * Author : ben */ #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <ctime> #include <iostream> #include <algorithm> #include <queue> #include <set> #include <map> #include <stack> #include <string> #include <vector> #include <deque> #include <list> #include <functional> #include <numeric> #include <cctype> using namespace std; const int MAX_ORDER = 2; int MOD; typedef long long typec; typedef struct MyMatrix { int row, col; typec num[MAX_ORDER][MAX_ORDER]; MyMatrix(int rr, int cc) { row = rr; col = cc; } inline void init() { memset(num, 0, sizeof(num)); } } MyMatrix; //矩阵乘法。注意:ma.col与mb.row一定要相等,否则会出问题 MyMatrix operator*(MyMatrix ma, MyMatrix mb) { int row = ma.row; int col = mb.col; int K = ma.col; MyMatrix numc(row, col); numc.init(); int i, j, k; for (i = 0; i < row; i++) { for (j = 0; j < col; j++) { for (k = 0; k < K; k++) { numc.num[i][j] += ma.num[i][k] * mb.num[k][j]; numc.num[i][j] %= MOD; } } } return numc; } //矩阵快速幂。注意:ma.col与ma.row一定要相等,否则会出问题 MyMatrix mpow(MyMatrix ma, int x) { int ord = ma.row; MyMatrix numc(ord, ord); numc.init(); for (int i = 0; i < ord; i++) { numc.num[i][i] = 1; } for (; x; x >>= 1) { if (x & 1) { numc = numc * ma; } ma = ma * ma; } return numc; } inline MyMatrix getori() { MyMatrix ori(1, 2); ori.num[0][0] = 0; ori.num[0][1] = 1; return ori; } inline MyMatrix gettran() { MyMatrix tran(2, 2); tran.num[0][0] = 0; tran.num[0][1] = 1; tran.num[1][0] = 1; tran.num[1][1] = 3; return tran; } int main() { #ifndef ONLINE_JUDGE freopen("data.in", "r", stdin); #endif long long temp; while(scanf("%I64d", &temp) == 1) { int n = (int)(temp % 240); MOD = 183120; n = (getori() * mpow(gettran(), n)).num[0][0]; MOD = 222222224; n = (getori() * mpow(gettran(), n)).num[0][0]; MOD = 1000000007; n = (getori() * mpow(gettran(), n)).num[0][0]; printf("%d\n", n); } return 0; }