HDU1757题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1757
这道题做了一下午- -,主要是卡在了矩阵构造上,该题的数据为( k<2*10^9 , m < 10^5 ),k很大,可以看出递推求出每一个f(k)肯定会超时的,所以想到了矩阵连乘,再运用二分法求解,够早的矩阵如下:
(f(9),f(8),f(7),f(6),f(5),f(4),f(3),f(2),f(1),f(0))*
=(f(10),f(9),f(8),f(7),f(6),f(5),f(4),f(3),f(2),f(1));
所以求f(10)只需求(f(9),f(8),f(7),f(6),f(5),f(4),f(3),f(2),f(1),f(0))*矩阵的一次方就行了,
若求f(k)当k>=10时,乘以矩阵的(k-9)次方即可;
然后再用二分法,求矩阵连乘的结果,AC代码如下:
#include<iostream> using namespace std; #include<string.h> int d[10][10],t[10][10],t1[10][10];//数组t和t1都是中间量 void fun(int n,int m,int a[])//二分法 多练习多思考就会明白 { int i,j,k; if(n==1)//n=1的情况 终结递归的条件 { memset(d,0,sizeof(d)); for(i=0;i<10;i++) for(j=0;j<10;j++) { if(j==0)d[i][j]=a[i]; if(j-i==1)d[i][j]=1; } return ;//返回 } if(n%2==0)//n为偶数时 { n/=2; fun(n,m,a); for(i=0;i<10;i++) for(j=0;j<10;j++) t[i][j]=d[i][j]; for(i=0;i<10;i++) for(j=0;j<10;j++) { int s=0; for(k=0;k<10;k++) s+=t[i][k]*t[k][j]; d[i][j]=s%m; } return ; } else //n为奇数时 { n/=2; fun(n,m,a); for(i=0;i<10;i++) for(j=0;j<10;j++) t[i][j]=d[i][j]; for(i=0;i<10;i++) for(j=0;j<10;j++) { int s=0; for(k=0;k<10;k++) s+=t[i][k]*t[k][j]; d[i][j]=s%m; } //再乘以基本矩阵 for(i=0;i<10;i++)//数组t和t1都是为了存取数组d的中间结果 for(j=0;j<10;j++) t[i][j]=d[i][j]; memset(t1,0,sizeof(t1)); for(i=0;i<10;i++) for(j=0;j<10;j++) { if(j==0)t1[i][j]=a[i]; if(j-i==1)t1[i][j]=1; } for(i=0;i<10;i++) for(j=0;j<10;j++) { int s=0; for(k=0;k<10;k++) s+=t[i][k]*t1[k][j]; d[i][j]=s%m; } return ; } } int main() { //freopen("d:\\1.txt","r",stdin); int k,m; int a[10]; int i,s; while(scanf("%d%d",&k,&m)!=EOF) { for(i=0;i<10;i++) cin>>a[i]; if(k<10) printf("%d\n",k%m); else { fun((k-9),m,a); s=0; for(i=0;i<10;i++) s+=(9-i)*d[i][0]; //直接求出结果 cout<<s%m<<endl; } } return 0; }