文章目錄
題目描述
SBB的媽媽SAA和SBB的爸爸SCC對他要求特別嚴格,每次吃飯之前都要SBB做出一道數學題目,不然就不允許吃飯。現在SCC的題目來了假設碗裡有n粒飯,SBB每次最多可以從碗裡取出m粒吃,最少取出1粒,問SBB有多少種吃法可以把碗裡的飯吃完,由於結果可能會很大,所以要把最終的答案對P模數。SBB對這道題毫無頭緒,於是他發了一條簡訊給你這個好朋友,求你協助他。
輸入
第一行為範例的數目T(T <= 100)。
每個範例由三個數n(1 <= n <= 10^9),m(1 <= m <= 10)和P(1 <= P <= 10^6)組成。
輸出
對於每個範例輸出一行,結果為SBB吃飯的方法數目對P模數。
範例輸入
3
4 1 3
3 2 3
4 2 6
範例輸出
1
0
5
Source
XTU OnlineJudge
這道題想了很久,哎!最近終於做出來了!!覺得解脫了!呵呵...
這道題如果只是類比計算過程的話,不用說會逾時(1<=n<=10^9)。但用矩陣運算和二分法去實現,竟44ms就AC了!!
首先,已知n,m,p,剛吃飯的吃法總共有
f(n)=f(n-1)+f(n-2)+...+f(n-m) (m-m>=0);
當m=1時,為常數數列{1}。
當m=2j時,f(n)=f(n-1)+f(n-2),為斐波拉契數列;
用二分法進行矩陣冪運算。
當 m=3時,構造矩陣.............
完了。
#include<iostream><br />#include<cmath><br />using namespace std;</p><p>__int64 rec[30][10][10];<br />__int64 n,m,p;</p><p>void multi(__int64 s[][10], __int64 a[][10], __int64 b[][10], __int64 size)<br />{<br />__int64 i,j,k;<br />__int64 x[10][10], y[10][10];<br />for(i=0; i<size; i++)<br />for(j=0; j<size; j++)<br />{<br />x[i][j]=a[i][j];<br />y[i][j]=b[i][j];<br />}</p><p>for(i=0; i<size; i++)<br />for(j=0; j<size; j++)<br />{<br />s[i][j] = 0;<br />for(k=0; k<size; k++)<br />s[i][j] = (x[i][k]*y[k][j]+s[i][j])%p;<br />}<br />}</p><p>int main()<br />{<br />int i,j,k,t;<br />__int64 a[10][10];</p><p>scanf("%I64d",&t);<br />while(t--)<br />{<br />cin>>n>>m>>p;</p><p>for(i=0; i<m; i++)<br />for(j=0; j<m; j++)<br />if(j==0)<br />rec[0][i][j]=1;<br />else if(j==i+1)<br />rec[0][i][j]=1;<br />else<br />rec[0][i][j]=0;</p><p>for(i=1; i<30; i++)<br />multi(rec[i], rec[i-1], rec[i-1], m);</p><p>memset(a, 0, sizeof(a));<br />for(i=0; i<m; i++)<br />for(j=0; j<m; j++)</p><p>if(m-1-i-j>0)<br />a[i][j]=(1<<(m-2-i-j));<br />else if(m-1-i-j==0)<br />a[i][j]=1;</p><p>for(i=0; i<30; i++)<br />{<br />if(n&(1<<i))<br />multi(a, a, rec[i], m);<br />}<br />printf("%I64d/n",a[0][m-1]%p);<br />}<br />return 0;<br />}