Description
给定两个巨大的方块矩阵 A A A和 B B B (行数高达 7000 7000 7000).请输出 A × B A\times B A×B 的运算结果,且时限只有 2 s 2s 2s。
哈哈!对矩阵乘法的演进历史有些涉猎的人,应该能感受到在某 C P C CPC CPC上出现这样的题目有多不合理。
为了使这个问题成为可能(?),我们将减小 I / O I / O I/O大小。
现在,给定 a , b , c , d a,b,c,d a,b,c,d的四个种子可以通过 X o r s h i f t Xorshift Xorshift随机数生成器生成输入矩阵。
这里是通过随机数生成器来产生矩阵的实现:
uint32_t x, y, z, w;
uint32_t xorshift() {
uint32_t t = x;
t ^= t << 11;
t ^= t >> 8;
x = y; y = z; z = w;
w ^= w >> 19;
w ^= t;
return w & ((1 << 24) - 1);
}
void getInputMatrix(
int n, uint32_t matrix[][7000],
uint32_t a, uint32_t b, uint32_t c, uint32_t d
) {
x = a; y = b; z = c; w = d;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
matrix[i][j] = xorshift();
}
}
}
另外,您应该将输出矩阵传递给哈希函数 ( h a s h f u n c t i o n ) (hash function) (hashfunction)。
我们会给你另一个数字 p p p来做这件事。
这里是哈希函数的实现。
const int MOD = 1000000007;
int hash(int n, long long matrix[][7000], int p) {
long long v = 0;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
v *= p;
v += matrix[i][j];
v %= MOD;
}
}
return v;
}
Input
输入只包含一行,包含十个整数 n , A a , A b , A c , A d , B a , B b , B c , B d , p n,A_a,A_b,A_c,A_d,B_a,B_b,B_c,B_d,p n,Aa,Ab,Ac,Ad,Ba,Bb,Bc,Bd,p。
矩阵 A A A是通过 n , A a , A b , A c , A d n,A_a,A_b,A_c,A_d n,Aa,Ab,Ac,Ad构建 g e t I n p u t M a t r i x ( ) getInputMatrix() getInputMatrix()的。
矩阵 B B B是通过 n , B a , B b , B c , B d n,B_a,B_b,B_c,B_d n,Ba,Bb,Bc,Bd构建 g e t I n p u t M a t r i x ( ) getInputMatrix() getInputMatrix()的。
p p p是哈希函数。
( 1 ≤ n ≤ 2000 , 1 ≤ A a , A b , A c , A d , B a , B b , B c , B d < 2 32 , 2 ≤ p < 1 0 9 + 7 ) (1\le n\le 2000,1\le A_a,A_b,A_c,A_d,B_a,B_b,B_c,B_d< 2^{32},2\le p<10^9+7) (1≤n≤2000,1≤Aa,Ab,Ac,Ad,Ba,Bb,Bc,Bd<232,2≤p<109+7)
Output
令 C = A × B C = A \times B C=A×B, C C C 是 A A A矩阵乘以 B B B 的结果
请输出一个整数,它是$hash(n,C,p) $的结果
Sample Input
1 2 3 4 5 6 7 8 9 10
Sample Output
50873769
Solution
a
n
s
=
∑
i
=
0
n
−
1
∑
j
=
0
n
−
1
C
i
j
⋅
p
(
n
−
1
−
i
)
⋅
n
+
(
n
−
1
−
j
)
=
∑
i
=
0
n
−
1
∑
j
=
0
n
−
1
∑
k
=
0
n
−
1
A
i
k
⋅
B
k
j
⋅
p
(
n
−
1
−
i
)
⋅
n
+
(
n
−
1
−
j
)
=
∑
k
=
0
n
−
1
(
∑
i
=
0
n
−
1
A
i
k
⋅
p
(
n
−
1
−
i
)
⋅
n
)
⋅
(
∑
j
=
0
n
−
1
B
k
j
⋅
p
n
−
1
−
j
)
\begin{array}{lcl} ans&=&\sum\limits_{i=0}^{n-1}\sum\limits_{j=0}^{n-1}C_{ij}\cdot p^{(n-1-i)\cdot n+(n-1-j)}\\ &=&\sum\limits_{i=0}^{n-1}\sum\limits_{j=0}^{n-1}\sum\limits_{k=0}^{n-1}A_{ik}\cdot B_{kj}\cdot p^{(n-1-i)\cdot n+(n-1-j)}\\ &=&\sum\limits_{k=0}^{n-1}(\sum\limits_{i=0}^{n-1}A_{ik}\cdot p^{(n-1-i)\cdot n})\cdot (\sum\limits_{j=0}^{n-1}B_{kj}\cdot p^{n-1-j}) \end{array}
ans===i=0∑n−1j=0∑n−1Cij⋅p(n−1−i)⋅n+(n−1−j)i=0∑n−1j=0∑n−1k=0∑n−1Aik⋅Bkj⋅p(n−1−i)⋅n+(n−1−j)k=0∑n−1(i=0∑n−1Aik⋅p(n−1−i)⋅n)⋅(j=0∑n−1Bkj⋅pn−1−j)
时间复杂度降为
O
(
n
2
)
O(n^2)
O(n2),注意到直接开空间存
A
,
B
A,B
A,B会爆内存,直接维护
a
k
=
∑
i
=
0
n
−
1
A
i
k
⋅
p
(
n
−
1
−
i
)
⋅
n
,
b
k
=
∑
j
=
0
n
−
1
B
k
j
⋅
p
n
−
1
−
j
a_k=\sum\limits_{i=0}^{n-1}A_{ik}\cdot p^{(n-1-i)\cdot n},b_k=\sum\limits_{j=0}^{n-1}B_{kj}\cdot p^{n-1-j}
ak=i=0∑n−1Aik⋅p(n−1−i)⋅n,bk=j=0∑n−1Bkj⋅pn−1−j
Code
#include<cstdio>
using namespace std;
typedef long long ll;
typedef unsigned uint32_t;
const int maxn=7000;
uint32_t x,y,z,w;
uint32_t xorshift()
{
uint32_t t=x;
t^=t<<11;
t^=t>>8;
x=y;y=z;z=w;
w^=w>>19;
w^=t;
return w&((1<<24)-1);
}
#define mod 1000000007
int mul(int x,int y)
{
ll z=1ll*x*y;
return z-z/mod*mod;
}
int add(int x,int y)
{
x+=y;
if(x>=mod)x-=mod;
return x;
}
uint32_t Aa,Ab,Ac,Ad,Ba,Bb,Bc,Bd,p;
int n,f[maxn],g[maxn],A[maxn],B[maxn];
int main()
{
scanf("%d%u%u%u%u%u%u%u%u%u",&n,&Aa,&Ab,&Ac,&Ad,&Ba,&Bb,&Bc,&Bd,&p);
p%=mod;
f[0]=g[0]=1;
for(int i=1;i<n;i++)f[i]=mul(f[i-1],p);
p=mul(f[n-1],p);
for(int i=1;i<n;i++)g[i]=mul(g[i-1],p);
x=Aa,y=Ab,z=Ac,w=Ad;
for(int i=0;i<n;i++)
for(int k=0;k<n;k++)
A[k]=add(A[k],mul(xorshift(),g[n-1-i]));
x=Ba,y=Bb,z=Bc,w=Bd;
for(int k=0;k<n;k++)
for(int j=0;j<n;j++)
B[k]=add(B[k],mul(xorshift(),f[n-1-j]));
int ans=0;
for(int k=0;k<n;k++)ans=add(ans,mul(A[k],B[k]));
printf("%d\n",ans);
return 0;
}