题目很水,但是思想很重要
是递推啊......是递推啊......
没错真的是非常简单的递推,你没有判断错误!
你每次可以上1个台阶,上2个台阶,上3个台阶,给出n级台阶。问你有几种走法?
我强迫症范的时候,会一次上一个台阶,走错了,会重新走一遍。
那么递推公式非常简单的出来了:
an=an-1+an-2+an-3
当n=1的时候为1,当n=2的时候为2,当n=3的时候为4;
即a[1]=1,a[2]=2,a[3]=4;
当n的时候,将规模缩小到n-1,即最后一步走一个台阶,那么有a[n-1]种方法;
若最后一次走两个台阶,那么有a[n-2]种方法,最后一次走三个台阶,那么有a[n-3]种方法。
递推公式就这么出来了。
一般情况,我们都会使用数组存储,一次性算完,然后直接输出。显然,n的规模10^9
显然数组是做不到的。若是循环算的话,那时间想想也是醉了。
因此这里引入了一个新的方法,优化递推公式(应该只适用于一阶方程):
/**本题为递推公式的优化**/ #include <iostream> using namespace std; #include <stdio.h> #include <string.h> #define mod 1000000007 ///递推公式为an=an-1+an-2+an-3 void mul(long long a[][3],long long b[][3]) { long long c[3][3]; for(int i=0;i<3;i++) for(int j=0;j<3;j++){ c[i][j]=0; for(int k=0;k<3;k++) c[i][j]+=((a[i][k]%mod)*(b[k][j]%mod))%mod; } for(int i=0;i<3;i++) for(int j=0;j<3;j++) b[i][j]=c[i][j]%mod; } long long quickPow(long long n,long long a[][3],long long b[][3]) { while(n) { if(n&1) mul(a,b); n=n>>1; mul(a,a); } return b[0][0]; } int main() { long long T,k,n; scanf("%lld",&T); for(k=1;k<=T;k++) { scanf("%lld",&n); long long stairs[3][3]={4,0,0,2,0,0,1,0,0};///初始化更新还有什么清空的都要注意 long long co[3][3]={1,1,1,1,0,0,0,1,0}; printf("Case %lld:\n",k); switch(n){ case 0:printf("1\n");break; case 1:printf("1\n");break; case 2:printf("2\n");break; case 3:printf("4\n");break; default:printf("%lld\n",quickPow(n-3,co,stairs));break;///注意这里的n-3 } /* if(n==0) printf("1\n"); else if(n == 1) printf("1\n"); else if(n == 2) printf("2\n"); else printf("%lld\n",quickPow(n-3,co,stairs));*/ } return 0; }