HDU 6185 Covering 矩阵快速幂 递推
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6185
题目描述: 一个4*n的矩形, 你用1*2的矩形覆盖有多少种方案, n <= 1e18
解题思路: 自己看题一开始以为是轮廓线DP, 后来发现n实在是太大了....数组根本开不下, 后来觉得应该是一个矩阵快速幂, 可是递推式自己求不出来。 其实递推式应该打表出前十个n再去求, 因为我们这是一个线性递推式
f(n) = k1 * f(n-1) + k2 * f(n-2) + ...... kw * f(n-w)
我们从f(n-1) + f(n-2) 开始去找, 如果找到的k都是整数的话, 那这个递推式就是正确的, 因为这个递推式的几何意义表示在完成f(n-w)的前提下 前面那些有多少种方案, 而方案数一定是整数, 所以保证了正确性........现在我们先借助求得的前十个答案来求k, 当w = 2 , 3的情况下k都存在小数, 当w = 4的时候全部是整数
代码:
#include <iostream> #include <cstdio> #include <string> #include <vector> #include <cstring> #include <iterator> #include <cmath> #include <algorithm> #include <stack> #include <deque> #include <map> #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 #define mem0(a) memset(a,0,sizeof(a)) #define sca(x) scanf("%d",&x) #define de printf("=======\n") typedef long long ll; using namespace std; const int maxn = 105; typedef double Matrix[maxn][maxn]; Matrix A, X; void gauss(Matrix A,int n) { int i,j,k,r; for(int i=0; i<n; i++) { r=i; for( j=i+1; j<n; j++) if(fabs(A[j][i])>fabs(A[r][i]))r=j; if(r!=i) for(j=0; j<=n; j++)swap(A[r][j],A[i][j]); for(k=i+1; k<n; k++) { double f=A[k][i]/A[i][i]; for(j=i; j<=n; j++) A[k][j]-=f*A[i][j]; } } for(i=n-1; i>=0; i--) { for(j=i+1; j<n; j++) A[i][n]-=A[j][n]*A[i][j]; A[i][n]/=A[i][i]; } } int main() { mem0(A); A[0][0]=95,A[0][1]=36,A[0][2]=11,A[0][3]=5,A[1][0]=6336,A[1][1]=2245,A[1][2]=781; A[1][3]=281,A[2][0]=781,A[2][1]=281,A[2][2]=95,A[2][3]=36,A[3][0]=2245,A[3][1]=781; A[3][2]=281,A[3][3]=95,A[0][4]=281,A[1][4]=18061,A[2][4]=2245,A[3][4]=6336; gauss(A, 4); for( int i = 0; i < 4; i++ ) { cout << A[i][4] << endl; } return 0; }
系数是1, 5, 1, -1, 所以递推式就是f(n) = f(n-1)+5f(n-2)+f(n-3)-f(n-4)
这时候我们就可以根据这个求矩阵快速幂的矩阵了...........
写了一个多点儿......又出现BUG了.....不容易啊....
代码:
#include <iostream> #include <cstdio> #include <string> #include <vector> #include <cstring> #include <iterator> #include <cmath> #include <algorithm> #include <stack> #include <deque> #include <map> #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 #define mem0(a) memset(a,0,sizeof(a)) #define sca(x) scanf("%d",&x) #define de printf("=======\n") typedef long long ll; using namespace std; const ll mod = 1e9+7; const int maxn = 4; const int temp = 4; const int a[4] = {36,11,5,1}; typedef struct { ll mat[maxn][maxn]; void init() { mem0(mat); for( int i = 0; i < temp; i++ ) { for( int j = 0; j < temp; j++ ) { if( i == j ) mat[i][j] = 1; } } } } Matrix; Matrix matrix = {1,5,1,-1,1,0,0,0,0,1,0,0,0,0,1,0}; Matrix mul( Matrix m1, Matrix m2 ) { Matrix ret; mem0(ret.mat); for( int i = 0; i < temp; i++ ) { for( int j = 0; j < temp; j++ ) { for( int k = 0; k < temp; k++ ) { ret.mat[i][j] = (ret.mat[i][j] + (m1.mat[i][k]*m2.mat[k][j])+mod) % mod; // cout << ret.mat[i][j] << endl; } } } return ret; } Matrix matrix_quick_power( Matrix m, ll times ) { Matrix ret; ret.init(); while( times ) { if( times & 1 ) ret = mul( ret, m ); times >>= 1; m = mul(m, m); } return ret; } int main() { // debug(matrix); // debug(matrix_quick_power( matrix, 1)); ll n; while( cin >> n ) { if( n == 1 ) { cout << 1 << endl; } else if( n == 2 ) { cout << 5 << endl; } else if( n == 3 ) { cout << 11 << endl; } else if( n == 4 ) { cout << 36 << endl; } else { Matrix res; res.init(); res = matrix_quick_power(matrix, n-4); ll ans = 0; for( int i = 0; i < 4; i++ ) { ans = (ans + res.mat[0][i]*a[i] + mod) % mod; } cout << ans << endl; } } return 0; }
思考: 这里明确一个问题, 我看到其他博客里会有这样的写法, typedef double Matrix[4][4], 这里解释一样, 这个时候Matrix 代表的就是一个4*4的整型数组, Matrix A , A就是那个数组, 但是和二维数组不一样的是, 这里的A可以传进函数里做实参, 但是为什么呢?, 然后我看到函数声明是这样显示的 double (*A)[], 这样就能作为实参传进去了吗........我还是很弱, 得多学点儿......真的菜................||分割 分割 分割|| 刚才学长在群里说了一下想明白了......原来传的就是一个指针........如果想传实参的话用vector<vector<double>>就可以了.....OK, 过
posted on 2017-09-01 13:39 FriskyPuppy 阅读(310) 评论(0) 编辑 收藏 举报