HDU 1757 A Simple Math Problem

来源:互联网 发布:linux 改主机名 编辑:程序博客网 时间:2024/06/07 00:54

Lele now is thinking about a simple function f(x). 

If x < 10 f(x) = x. 
If x >= 10 f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10); 
And ai(0<=i<=9) can only be 0 or 1 . 

Now, I will give a0 ~ a9 and two positive integers k and m ,and could you help Lele to caculate f(k)%m. 
Input
The problem contains mutiple test cases.Please process to the end of file. 
In each case, there will be two lines. 
In the first line , there are two positive integers k and m. ( k<2*10^9 , m < 10^5 ) 
In the second line , there are ten integers represent a0 ~ a9. 
Output
For each case, output f(k) % m in one line.
Sample Input
10 99991 1 1 1 1 1 1 1 1 120 5001 0 1 0 1 0 1 0 1 0
Sample Output
45104

一般矩阵乘法采用朴素的O(n^3)的算法:

 Mat operator*(Mat a,Mat b)  
 {  
     int i,j,k;  
     Mat c;  
     for (i=0;i<len;i++)  
     {  
         for (j=0;j<len;j++)  
         {  
             c.mat[i][j] = 0;  
             for(k=0;k<len;k++)  
                 c.mat[i][j]+=(a.mat[i][k]*b.mat[k][j])%MOD;  
         }  
     }  
     return c;  
 }

在ACM的题目中,我们一般考虑的是n阶方阵之间的乘法以及n阶方阵与n维向量(把向量看成n×1的矩阵)的乘法。矩阵乘法最重要的性质就是满足结合律,同时它另一个很重要的性质就是满足交换率,这保证了矩阵的幂运算满足快速幂取模(A^x % MOD)算法:

假设k = 27,则k的二进制表示为11011,所以

,可以看出:k的二进制的每一位矩阵A都要平方,在k二进制为1的位:末矩阵×平方后的A,在k二进制为0的位则末矩阵×E(单位矩阵),即不变。代码如下:

Mat operator^(Mat a,int x)  
 {  
     Mat p = e,q = a;  
     while (x)  
     {  
         if(x&1)  
             p = p*q;  
         x>>=1;  
         q = q*q;  
     }  
     return p;  
 }

许多题目还要求S = A + A2 + A3 + … +Ak.。其实再作一次二分即可:只需计算log(n)个A的幂即可。

Mat solve(Mat a,int p)  
 {  
     if(p==1)  
         return a; 
     /*如果p为奇数,则对p-1进行二分,a^p+二分结果*/ 
     /*
           A^1+A^2+A^3+A^4+A^5+A^6+A^7 = (A^1+A^2+A^3)+ A^3*(A^1+A^2+A^3)+A^7=A^7+solve(A,p-1)
     */
     else if(p&1)  
         return (a^p)+solve(a,p-1);  
     /*p为偶数,则直接二分*/
     /*
     A^1+A^2+A^3+A^4+A^5+A^6 = (A^1+A^2+A^3)+ A^3*(A^1+A^2+A^3) = (A^3+e)*(A^1+A^2+A^3)
     推广即可得到当p为偶数时   A^1+A^2+A^3+……+A^p = (A^(p/2)+e) * solve(A,p/2);
     */
     else  
         return ((a^(p>>1))+e)*solve(a,p>>1);  
 }  


构建矩阵
|f(10) |      |a0 a1 a2 ...a8 a9|   |f(9)|
| f(9) |       | 1  0  0 ... 0  0|          |f(8)|
| .....|  =     |.. ... ... ... ..|                 | .. |
| f(2) |       | 0  0  0 ... 0  0|          |f(1)|
| f(1) |       | 0  0  0 ... 1  0|          |f(0)|
#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<vector>#include<stack>#include<set>#include<map>#include<queue>#include<algorithm>using namespace std;struct stu{    int mtr[10][10];}a,b,c;int m;int n;struct stu mult(struct stu a1,struct stu a2){    struct stu temp;    int i,j,k;    for(i=0;i<10;i++){        for(j=0;j<10;j++){            temp.mtr[i][j]=0;            for(k=0;k<10;k++){                temp.mtr[i][j]+=(a1.mtr[i][k]*a2.mtr[k][j])%m;            }            temp.mtr[i][j]%=m;        }    }    return temp;};struct stu bin(int cnt){    struct stu tmp;    if(cnt==1)        return a;    if(cnt%2==0){        tmp=bin(cnt/2);return mult(tmp,tmp);    }    else{        tmp=bin((cnt-1)/2);        tmp=mult(tmp,tmp);        return mult(tmp,a);    }};int main(){    int i,j,k;    while(~scanf("%d %d",&n,&m)){        memset(a.mtr,0,sizeof(a.mtr));        for(i=1;i<10;i++)            a.mtr[i][i-1]=1;        for(i=0;i<10;i++)            scanf("%d",&a.mtr[0][i]);        if(n<10){            printf("%d\n",n%m);            continue;        }        n-=9;        c=bin(n);        int ans=0;        for(i=0;i<10;i++)            ans+=(c.mtr[0][i]*(9-i))%m;        printf("%d\n",ans%m);    }    return 0;}


0 0
原创粉丝点击