存在以下遞推式:
F(n+1)=A1*F(n)+A2*F(n-1)+...+An*F(1)
求第K項的值對1000000007取模的結果
單組測試數據php
第一行輸入兩個整數 n , k (1<=n<=100,n<k<=10000000000)ios
第二行輸入 n 個整數 F(1) F(2) ... F(n)數組
第三行輸入 n 個整數A1 A2 ... An 函數
輸出一個整數學習
2 3
1 2
3 4
10
今天作這個題,發現這個題真乃卡時間的神題...讓我學到了不少..
- 第一個是我像平時同樣上快速冪的模板,返回一個矩陣結構體,可是我發現連跑都跑不了 = =,後面發現是因爲矩陣結構體內開了一個 200*200 的二維數組,二函數返回不了這麼大空間的結構體,
我開始一直覺得玄學,一直改一直改,改了1個多小時,後來把常量改爲 100,沒想到就能夠跑了,居然是這個緣由,又學習到一個!
- 第二個是我改了以後AC不了,一直提醒時間超限,而後羣裏dalao教我新姿式:優化的矩陣乘法和滾動數組.
Matrix mult(Matrix a,Matrix b,int n) { Matrix temp; for(int i=0; i<n; i++) { for(int k=0; k<n; k++) { if(a.v[i][k] == 0 ) continue; for(int j=0; j<n; j++) { temp.v[i][j] = (temp.v[i][j]+(a.v[i][k]*b.v[k][j])%mod)%mod; } } } return temp; }
之前的:測試
Matrix mult(Matrix a,Matrix b,int n){ Matrix temp; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ for(int k=0;k<n;k++){ temp.v[i][j] = (temp.v[i][j]+(a.v[i][k]*b.v[k][j])%mod)%mod; } } } return temp; }
這個技巧十分有用!特別是當矩陣高階而且稀疏的時候~優化
滾動數組的優化就真的玄學了...我也不知道爲何快..ui
這個題的係數矩陣是:spa
A1 A2 ... AN 1 0 ... 0 0 1 ... 0 .... 0 0 ... 1 0
AC代碼:指針
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <map> #include <vector> using namespace std; typedef long long LL; const LL mod = 1000000007; const int N = 102; LL f[N]; struct Matrix { LL v[N][N]; Matrix() { memset(v,0,sizeof(v)); } } M[2]; Matrix mult(Matrix a,Matrix b,int n) { Matrix temp; for(int i=0; i<n; i++) { for(int k=0; k<n; k++) { if(a.v[i][k] == 0 ) continue; for(int j=0; j<n; j++) { temp.v[i][j] = (temp.v[i][j]+(a.v[i][k]*b.v[k][j])%mod)%mod; } } } return temp; } void pow_mod(LL t,LL n) { for(int i=0; i<n; i++) { M[0].v[i][i] = 1; } while(t) { if(t&1) M[0] = mult(M[0],M[1],n); M[1] = mult(M[1],M[1],n); t>>=1; } } int main() { int n; LL k; scanf("%d%lld",&n,&k); for(int i=0; i<n; i++) { scanf("%lld",&f[n-1-i]); } for(int i=0; i<n; i++) { scanf("%lld",&M[1].v[0][i]); } for(int i=1; i<n; i++) { M[1].v[i][i-1] = 1; } k = k-n; pow_mod(k,n); LL ans = 0; for(int i=0; i<n; i++) { ans=(ans+M[0].v[0][i]*f[i]%mod)%mod; } printf("%lld\n",ans); return 0; }
弄了一個矩陣快速冪新板子:
typedef struct Matrix { LL m[maxn][maxn]; LL r; LL c; Matrix(){ r = c = 0; memset(m, 0, sizeof(m)); } } Matrix; Matrix mul(Matrix m1, Matrix m2, LL mod) { Matrix ans = Matrix(); ans.r = m1.r; ans.c = m2.c; for(LL i = 1; i <= m1.r; i++) { for(LL j = 1; j <= m2.r; j++) { for(LL k = 1; k <= m2.c; k++) { if(m2.m[j][k] == 0) continue; ans.m[i][k] = ((ans.m[i][k] + m1.m[i][j] * m2.m[j][k] % mod) % mod) % mod; } } } return ans; } Matrix quickmul(Matrix m, LL n, LL mod) { Matrix ans = Matrix(); for(LL i = 1; i <= m.r; i++) { ans.m[i][i] = 1; } ans.r = m.r; ans.c = m.c; while(n) { if(n & 1) ans = mul(m, ans, mod); m = mul(m, m, mod); n >>= 1; } return ans; }
滾動數組版:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <map> #include <vector> using namespace std; typedef long long LL; const LL mod = 1E9+7; const LL maxn = 110; LL n, k; LL f[maxn], a[maxn]; struct Matrix { LL m[maxn][maxn]; LL r; LL c; Matrix(){ r = c = 0; memset(m, 0, sizeof(m)); } } M[2]; Matrix mul(Matrix m1, Matrix m2, LL mod) { Matrix ans = Matrix(); ans.r = m1.r; ans.c = m2.c; for(LL i = 1; i <= m1.r; i++) { for(LL j = 1; j <= m2.r; j++) { for(LL k = 1; k <= m2.c; k++) { if(m2.m[j][k] == 0) continue; ans.m[i][k] = ((ans.m[i][k] + m1.m[i][j] * m2.m[j][k] % mod) % mod) % mod; } } } return ans; } void quickmul(LL n, LL mod) { for(LL i = 1; i <= M[1].r; i++) { M[0].m[i][i] = 1; } M[0].r = M[1].r; M[0].c = M[1].c; while(n) { if(n & 1) M[0] = mul(M[1], M[0], mod); M[1] = mul(M[1], M[1], mod); n >>= 1; } } int main() { int n; LL k; scanf("%d%lld",&n,&k); for(int i=1; i<=n; i++) { scanf("%lld",&f[n-i+1]); } M[1].c = M[1].r = n; for(int i=1; i<=n; i++) { scanf("%lld",&M[1].m[1][i]); } for(int i=2; i<=n; i++) { M[1].m[i][i-1] = 1; } k = k-n; quickmul(k,mod); LL ans = 0; for(int i=1; i<=n; i++) { ans=(ans+M[0].m[1][i]*f[i]%mod)%mod; } printf("%lld\n",ans); return 0; }
終極指針版(目前最快的):
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <map> #include <vector> using namespace std; typedef long long LL; const LL mod = 1000000007; const int N = 102; LL f[N]; struct Matrix { LL v[N][N]; Matrix(){memset(v,0,sizeof(v));} } M; Matrix* mult(Matrix *a,Matrix *b,int n) { Matrix * temp=(Matrix *)malloc(sizeof(M)); temp->v[0][0] = 0; // memset(temp->v,0,sizeof(temp->v)); for(int i=0; i<n; i++) { for(int k=0; k<n; k++) { if(a->v[i][k] == 0 ) continue; for(int j=0; j<n; j++) { temp->v[i][j] = (temp->v[i][j]+(a->v[i][k]*b->v[k][j])%mod)%mod; } } } return temp; } void pow_mod(Matrix *a,LL t,LL n) { Matrix * ans=(Matrix *)malloc(sizeof(M)); for(int i=0; i<n; i++) { ans->v[i][i] = 1; } while(t) { if(t&1) ans = mult(a,ans,n); a = mult(a,a,n); t>>=1; } LL res = 0; for(int i=0; i<n; i++) { res=(res+ans->v[0][i]*f[i]%mod)%mod; } printf("%lld\n",res); } int main() { int n; LL k; scanf("%d%lld",&n,&k); for(int i=0; i<n; i++) { scanf("%lld",&f[n-1-i]); } for(int i=0; i<n; i++) { scanf("%lld",&M.v[0][i]); } for(int i=1; i<n; i++) { M.v[i][i-1] = 1; } k = k-n; pow_mod(&M,k,n); return 0; }