URAL 1518 Jedi Riddle 3 矩阵快速幂

1518. Jedi Riddle 3

Time limit: 1.5 second
Memory limit: 64 MB

Background

The death is a funny thing. It is discussed only by the ones, who never died, while those, who are already dead, prefer keeping silence. That is why few people know, what exactly happens with a human after his death. A body is undoubtedly remains under ground forever... But the way of a soul was discovered only by Anton Hamster, who was a disciple of legendary Vasily Slipman (you may look through the problems  "Jedi riddle" and  "Jedi riddle 2" for more information about Mr. Slipman).
Mr. Hamster carried out a sequence of experiments and found out, that, however it sounds pity, a soul neither soars into the sky nor falls under ground. It just finds oneself at one of the countless levels of the Twilight, where it is condemned to stay till the end of time. In theory, a soul may be returned into the Real World and resurrected in a new body. The only question is how to do it...

Problem

Surely, Anton knew, that it was possible to get to any level of the Twilight straight from the Real World. You should only know a Key - and the Gates of the Twilight will open before you. Inter vivos, Mr. Slipman himself visited  N first levels using  N Keys  Ki he found by brute force. But Vasily failed to find the Key to the ( N+1)-th and the following levels. He just made a remark, that one had to use  N Shift Numbers  Ci and the Modular Number  Y.
But Mr. Hamster could excel his Teacher and succeeded in finding a universal formula for the Key  Kito the Gates of any level of the Twilight. Here is the formula:  Ki = ( Ki-1* CN +  Ki-2*CN-1 +  Ki-3*CN-2 + ... +  Ki-N*C1) modulo  Y.
And now Anton wants to organize the second coming of Mr. Slipman into our sinful world. The only thing he needs is to calculate the Key to the Gates of the Twilight's  X-th level, where the Teacher's soul is concealed in expectation of freedom.

Input

The first line contains the integer numbers  N (1 ≤  N ≤ 100),  X ( N <  X < 2 28) and  Y (2 ≤  Y < 2 28). The second line contains  N integer Keys  Ki (0 ≤  Ki ≤ 100). The third line contains  Ninteger Shift Numbers  Ci (0 ≤  Ci ≤ 1).

Output

You should output the desired Key  KX.

Sample

input output
3 6 73
12 91 65
1 1 0
22





就是 那个加粗的公式  写成矩阵相乘就ok了。 轻松a。 
矩阵快速幂100*100 大小的矩阵差不多极限了。

#include<stdio.h>
#include<string.h>
#define Matr 105 //矩阵大小,注意能小就小   矩阵从1开始   所以Matr 要+1 
#define ll __int64
struct mat//矩阵结构体,a表示内容,size大小 矩阵从1开始   但size不用加一
{
    ll a[Matr][Matr];
    mat()//构造函数
    {
        memset(a,0,sizeof(a));
    }
};
int Size;
ll mod ;

mat multi(mat m1,mat m2)//两个相等矩阵的乘法,对于稀疏矩阵,有0处不用运算的优化 
{
    mat ans=mat(); 
    for(int i=1;i<=Size;i++)
        for(int j=1;j<=Size;j++)
            if(m1.a[i][j])//稀疏矩阵优化 
                for(int k=1;k<=Size;k++)
                    ans.a[i][k]=(ans.a[i][k]+m1.a[i][j]*m2.a[j][k])%mod; //i行k列第j项
    return ans;
}

mat quickmulti(mat m,ll n)//二分快速幂 
{
    mat ans=mat();
    int i;
    for(i=1;i<=Size;i++)ans.a[i][i]=1;
    while(n)
    {
        if(n&1)ans=multi(m,ans);//奇乘偶子乘 挺好记的.
        m=multi(m,m);
        n>>=1;
    }
    return ans;
}

void print(mat m)//输出矩阵信息,debug用   
{  
    int i,j;  
    printf("%d\n",Size);  
    for(i=1;i<=Size;i++)  
    {  
        for(j=1;j<=Size;j++)
			printf("%d ",m.a[i][j]);  
        printf("\n");  
    }  
}  
int main()
{
	int n; 
	while(scanf("%d%d%d",&Size,&n,&mod)!=EOF) 
	{
		mat gouzao=mat(),chu=mat();
		for(int i=1;i<Size;i++)
			gouzao.a[i+1][i]=1;
		for(int i=1;i<=Size;i++)
			scanf("%I64d",&chu.a[1][i]);
		for(int i=1;i<=Size;i++)
			scanf("%I64d",&gouzao.a[i][Size]); 

		 

		printf("%I64d\n",multi(chu,quickmulti(gouzao,n-1)).a[1][1]); 
	}
	return 0;
}

/*
ans^=n -
mat ans=mat();
ans.size=Size;
初始化ans矩阵
ans=quickmulti(ans,n,mod);

void print(mat m)//输出矩阵信息,debug用 
{
    int i,j;
    printf(%dn,m.size);
    for(i=1;i=m.size;i++)
    {
        for(j=1;j=m.size;j++)printf(%d ,m.a[i][j]);
        printf(n);
    }
}
*/







你可能感兴趣的:(矩阵快速幂)