Time Limit: 3000MS Memory Limit: 131072K
Total Submissions: 35006 Accepted: 14029
Description
Given a n × n n × n n×n matrix A and a positive integer k, find the sum S = A + A 2 + A 3 + … + A k S = A + A2 + A3 + … + Ak S=A+A2+A3+…+Ak.
Input
The input contains exactly one test case. The first line of input contains three positive integers n (n ≤ 30), k (k ≤ 109) and m (m < 104). Then follow n lines each containing n nonnegative integers below 32,768, giving A’s elements in row-major order.
Output
Output the elements of S modulo m in the same way as A is given.
Sample Input
2 2 4
0 1
1 1
Sample Output
1 2
2 3
题目翻译
给定一个 n × n n×n n×n矩阵a和一个正整数k,求和 S = a + A 2 + A 3 + … + A k S=a+A2+A3+…+Ak S=a+A2+A3+…+Ak。
输入
只包含一个测试用例。输入的第一行包含三个正整数
n
(
n
≤
30
)
、
k
(
k
≤
1
0
9
)
和
m
(
m
<
1
0
4
)
n(n≤30)、k(k≤10^9)和m(m<10^4)
n(n≤30)、k(k≤109)和m(m<104)。然后跟随n行,每行包含
32768
32768
32768以下的n个非负整数,按照行的主要顺序给出A的元素。
输出
以与A相同的方式输出S模m的元素。
解题思路
考虑
1
×
2
1×2
1×2的矩阵
【
A
n
−
1
,
S
[
n
−
2
]
】
【A^n-1,S[n-2]】
【An−1,S[n−2]】,注意此1×2矩阵的2个元素都是r阶方阵!我们希望通过乘以某2×2的矩阵M,得到1×2的矩阵
【
A
n
,
S
[
n
−
1
]
】
=
【
A
n
−
1
∗
A
,
A
n
−
1
+
S
[
n
−
2
]
】
【A^n,S[n-1]】=【A^n-1*A, An-1+S[n-2]】
【An,S[n−1]】=【An−1∗A,An−1+S[n−2]】
容易构造出此矩阵M为:

其中4个元素均为r阶方阵,O表示r阶全0矩阵,E表示单位矩阵(主对角线上为1,其它全为0)。
问题解决。我们的复杂度是:
(
2
r
)
3
∗
l
o
g
n
(2r)3*logn
(2r)3∗logn
其实,这个矩阵就是那个流行方法中用到的,这里我们用前面几个问题的思想很容易构造出了这个 2 r ∗ 2 r 2r*2r 2r∗2r的矩阵。因此:此思想高效、一般、统一、和谐!
代码
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
long long nn,k,mm;
struct c{
long long n,m;
long long a[100][100];
}A,B,CC;
c operator *(c A,c B){
c C;
C.n=A.n,C.m=B.m;
for(int i=1;i<=C.n;i++)
for(int j=1;j<=C.m;j++)
C.a[i][j]=0;
for(int k=1;k<=A.m;k++)
{
for(int i=1;i<=C.n;i++)
for(int j=1;j<=C.m;j++)
C.a[i][j]=(C.a[i][j]+(A.a[i][k]*B.a[k][j])%mm)%mm;
}
return C;
}
void poww(long long x){
if(x==1)
{
B=A;
return;
}
poww(x>>1);
B=B*B;
if(x&1)
B=B*A;
}
int main(){
scanf("%lld%lld%lld",&nn,&k,&mm);
CC.n=nn,CC.m=2*nn;
A.n=2*nn,A.m=2*nn;
for(int i=1;i<=nn;i++)
for(int j=1;j<=nn;j++)
{
scanf("%lld",&CC.a[i][j]);
CC.a[i][j]=CC.a[i][j]%mm;
A.a[i][j]=CC.a[i][j];
}
for(int i=1;i<=nn;i++)
for(int j=nn+1;j<=2*nn;j++)
if(j-nn==i)
A.a[i][j]=1;
for(int i=nn+1;i<=2*nn;i++)
for(int j=nn+1;j<=2*nn;j++)
if(j==i)
A.a[i][j]=1;
poww(k);
CC=CC*B;
for(int i=1;i<=nn;i++)
{
for(int j=nn+1;j<=2*nn;j++)
printf("%lld ",CC.a[i][j]);
printf("\n");
}
}


851

被折叠的 条评论
为什么被折叠?



