Recursive sequence (矩陣快速冪)2016ACM/ICPC亞洲區瀋陽站
題目
Farmer John likes to play mathematics games with hisNcows. Recently, they are attracted by recursive sequences. In each turn, the cows would stand in a line, while John writes two positive numbersaandbon a blackboard. And then, the cows would say their identity number one by one. The first cow says the first number
Input
The first line of input contains an integer
Each case contains only one line with three numbersN,aaandbbwhereN,a,b<2^31as described above.
Output
For each test case, output the number of theNN-th cow. This number might be very large, so you need to output it modulo2147493647.
In the first case, the third number is $85 = 21+2+3^4
題意
題目給出這樣一個遞推公式:
f(n)=f(n-2)*2+f(n-1)+n^ 4
f(1)=a,
f(2)=b;
給出n,a,b求f(n)%2147493647;
根據遞推公式容易得出一個O(N)的暴力演算法。但這題的資料範圍為N,a,b<2^31 ,直接暴力肯定超時,要用O(1),O(lngn)或者是O(n^(1/2))的演算法才有可能ac
觀察這種遞推公式,發現我們可以使用矩陣快速冪來計算,矩陣快速冪的複雜度是O(m^3 *lngn)m是矩陣的大小,複雜度很小可以一試。
矩陣快速冪是定義一個狀態矩陣和一個轉移矩陣,前一個狀態矩陣乘轉移矩陣可得到後一個狀態矩陣。
這題和普通的矩陣快速冪有點區別,這題的遞推函式在混合了一個變數n^4。
所以我們這題首先要考慮的就是,如何從n^4推出(n+1)^4,我們發現通過二項式定理可以得出,(n+1)^4=n^4+4n^3+6n^2+4n+1
這樣就有f(n+1)=2*f(n-1)+f(n)+n^4+4n^3+6n^2+4n+1
不妨設狀態矩陣F(n-1)=[f(n-1),f(n),n^4,4n^3,6n^2,4n,1]
若F(n)=F(N-1)*A 即[f(n),f(n+1),(n+1)^4,4(n+1)^3,6(n+1)^2,4(n+1),1]=[f(n-1),f(n),n^4,4n^3,6n^2,4n,1]*A
計算得A=
{0,2,0,0,0,0,0}
{1,1,0,0,0,0,0}
{0,1,1,0,0,0,0}
{0,1,1,1,0,0,0}
{0,1,1,2,1,0,0}
{0,1,1,3,3,1,0}
{0,1,1,4,6,4,1}
AC程式碼
#include<iostream> #include<algorithm> #include<cstring> #include<vector> #include<set> using namespace std; typedef long long ll; const ll mod=2147493647; ll n; void mul(ll f[7],ll a[7][7]){ ll c[7]; memset(c,0,sizeof(c)); for(ll j=0;j<7;j++) for(ll k=0;k<7;k++) c[j]=(c[j]+(ll)f[k]*a[k][j])%mod; memcpy(f,c,sizeof(c)); } void mulself(ll a[7][7]){ ll c[7][7]; memset(c,0,sizeof(c)); for(ll i=0;i<7;i++) for(ll j=0;j<7;j++) for(ll k=0;k<7;k++) c[i][j]=(c[i][j]+(ll)a[i][k]*a[k][j])%mod; memcpy(a,c,sizeof(c)); } int main(){ ll t,a,b; scanf("%lld",&t); while(t--){ scanf("%lld%lld%lld",&n,&a,&b); ll f[]={a,b,16,32,24,8,1}; ll a[][7]={ {0,2,0,0,0,0,0}, {1,1,0,0,0,0,0}, {0,1,1,0,0,0,0}, {0,1,1,1,0,0,0}, {0,1,1,2,1,0,0}, {0,1,1,3,3,1,0}, {0,1,1,4,6,4,1}, }; n--; for(;n;n>>=1){ if(n&1)mul(f,a); mulself(a); } printf("%lld\n",f[0]); } scanf("%lld"); }