探索(數學)(矩陣快速冪)(快速乘)
阿新 • • 發佈:2018-10-17
lld over long 技術分享 好想 二維 name i++ ans
一句話題意:三維空間劃分四維空間,最多能劃分成多少個部分。
我們直接想四維的不好想,但是一般這種題我們考慮從低維開始做起。
在經過手算之後我們可以發現:
設\(f(x)\)為零維(點)切一維(線)最多劃分的部分,遞推式:\(f(x)=f(x-1)+1\)
設\(g(x)\)為一維(線)切二維(平面)最多劃分的部分,遞推式:\(g(x)=g(x-1)+f(x-1)\)
設\(k(x)\)為二維(平面)切三維(空間)最多劃分的部分,遞推式:\(k(x)=k(x-1)+g(x-1)\)
設\(h(x)\)為三維(空間)切四維最多劃分的部分,遞推式:\(h(x)=h(x-1)+k(x-1)\)
那麽我們很容易看出這是一個遞推。但是因為數據範圍很大,所以我們考慮構造矩陣進行矩陣快速冪加速運算。(不會打mathjax矩陣,只能湊合一下了)
1 1 0 0 0
0 1 1 0 0
0 0 1 1 0
0 0 0 1 1
0 0 0 0 1
然後初始矩陣[1,f(0),g(0),k(0),h(0)]
但是因為數據實在很大,矩陣快速冪進行乘的時候很可能炸long long,所以我們用快速乘來保證數在mod範圍內。
代碼如下:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define MAXN 40 using namespace std; long long n,m; long long f[MAXN]; struct Node{long long t[MAXN][MAXN];}; Node init; inline long long multi(long long x,long long y,long long mod) { long long ans=0; while(y) { if(y&1) ans=(ans+x)%mod; x=(x+x)%mod; y>>=1; } return ans%mod; } inline Node mul(Node x,Node y) { Node cur; for(int i=1;i<=5;i++) for(int j=1;j<=5;j++) cur.t[i][j]=0; for(int i=1;i<=5;i++) for(int j=1;j<=5;j++) for(int k=1;k<=5;k++) cur.t[i][j]=(cur.t[i][j]+multi(x.t[i][k],y.t[k][j],m))%m; return cur; } inline void solve() { long long cur[MAXN]; memset(cur,0,sizeof(cur)); for(int j=1;j<=5;j++) for(int k=1;k<=5;k++) cur[j]=(cur[j]+multi(f[k],init.t[k][j],m))%m; for(int i=1;i<=5;i++) f[i]=cur[i]; } int main() { freopen("discover.in","r",stdin); freopen("discover.out","w",stdout); scanf("%lld%lld",&n,&m); f[1]=1; f[2]=1; f[3]=1; f[4]=1; f[5]=1; for(int i=1;i<=5;i++) init.t[i][i]=1; init.t[1][2]=1; init.t[2][3]=1; init.t[3][4]=1; init.t[4][5]=1; while(n) { if(n&1) solve(); init=mul(init,init); n>>=1; } printf("%lld\n",f[5]%m); return 0; }
探索(數學)(矩陣快速冪)(快速乘)