XTU SBB的饭碗

题目描述
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> #include<cmath> using namespace std; __int64 rec[30][10][10]; __int64 n,m,p; void multi(__int64 s[][10], __int64 a[][10], __int64 b[][10], __int64 size) { __int64 i,j,k; __int64 x[10][10], y[10][10]; for(i=0; i<size; i++) for(j=0; j<size; j++) { x[i][j]=a[i][j]; y[i][j]=b[i][j]; } for(i=0; i<size; i++) for(j=0; j<size; j++) { s[i][j] = 0; for(k=0; k<size; k++) s[i][j] = (x[i][k]*y[k][j]+s[i][j])%p; } } int main() { int i,j,k,t; __int64 a[10][10]; scanf("%I64d",&t); while(t--) { cin>>n>>m>>p; for(i=0; i<m; i++) for(j=0; j<m; j++) if(j==0) rec[0][i][j]=1; else if(j==i+1) rec[0][i][j]=1; else rec[0][i][j]=0; for(i=1; i<30; i++) multi(rec[i], rec[i-1], rec[i-1], m); memset(a, 0, sizeof(a)); for(i=0; i<m; i++) for(j=0; j<m; j++) if(m-1-i-j>0) a[i][j]=(1<<(m-2-i-j)); else if(m-1-i-j==0) a[i][j]=1; for(i=0; i<30; i++) { if(n&(1<<i)) multi(a, a, rec[i], m); } printf("%I64d/n",a[0][m-1]%p); } return 0; }

 

 

你可能感兴趣的:(XTU SBB的饭碗)