Circulant Matrix
题目描述
Niuniu has recently learned how to use Gaussian elimination to solve systems of linear equations.
Given n and
a[i]
a
[
i
]
, where
n
n
is a power of , let’s consider an
n×n
n
×
n
matrix
A
A
.
The index of and
a[i]
a
[
i
]
are numbered from
0
0
.
The element satisfies
A[i][j]=a[ixorj]
A
[
i
]
[
j
]
=
a
[
i
x
o
r
j
]
,
XOR
Let
p=1000000007
p
=
1000000007
.
Consider the equation
Ax=b(modp)
A
x
=
b
(
mod
p
)
where
A
A
is an matrix, and
x
x
and are both
n×1
n
×
1
row vector.
Given
n,a[i],b[i]
n
,
a
[
i
]
,
b
[
i
]
, you need to solve the
x
x
.
For example, when , the equations look like
A[0][0]⋅x[0]+A[0][1]⋅x[1]+A[0][2]⋅x[2]+A[0][3]⋅x[3]=b[0](modp)A[1][0]⋅x[0]+A[1][1]⋅x[1]+A[1][2]⋅x[2]+A[1][3]⋅x[3]=b[1](modp)A[2][0]⋅x[0]+A[2][1]⋅x[1]+A[2][2]⋅x[2]+A[2][3]⋅x[3]=b[2](modp)A[3][0]⋅x[0]+A[3][1]⋅x[1]+A[3][2]⋅x[2]+A[3][3]⋅x[3]=b[3](modp)
A
[
0
]
[
0
]
⋅
x
[
0
]
+
A
[
0
]
[
1
]
⋅
x
[
1
]
+
A
[
0
]
[
2
]
⋅
x
[
2
]
+
A
[
0
]
[
3
]
⋅
x
[
3
]
=
b
[
0
]
(
mod
p
)
A
[
1
]
[
0
]
⋅
x
[
0
]
+
A
[
1
]
[
1
]
⋅
x
[
1
]
+
A
[
1
]
[
2
]
⋅
x
[
2
]
+
A
[
1
]
[
3
]
⋅
x
[
3
]
=
b
[
1
]
(
mod
p
)
A
[
2
]
[
0
]
⋅
x
[
0
]
+
A
[
2
]
[
1
]
⋅
x
[
1
]
+
A
[
2
]
[
2
]
⋅
x
[
2
]
+
A
[
2
]
[
3
]
⋅
x
[
3
]
=
b
[
2
]
(
mod
p
)
A
[
3
]
[
0
]
⋅
x
[
0
]
+
A
[
3
]
[
1
]
⋅
x
[
1
]
+
A
[
3
]
[
2
]
⋅
x
[
2
]
+
A
[
3
]
[
3
]
⋅
x
[
3
]
=
b
[
3
]
(
mod
p
)
and the matrix
A
A
can be decided by the array .
It is guaranteed that there is a unique solution x x for these equations.
Input
The first line contains an integer, which is .
The second line contains
n
n
integers, which are the array .
The third line contains
n
n
integers, which are the array .
1<=n<=262144
1
<=
n
<=
262144
p=1000000007
p
=
1000000007
0<=a[i]<p
0
<=
a
[
i
]
<
p
0<=b[i]<p
0
<=
b
[
i
]
<
p
Output
The output should contains
n
n
lines.
The -th(index from
0
0
) line should contain .
x[i]
x
[
i
]
is an integer, and should satisfy
0<=x[i]<p
0
<=
x
[
i
]
<
p
.
问题分析
首先,我们通过观察题目得到
将矩阵 A A 展开
我们可以发现这个矩阵左上角和右下角相同,左下角和右上角相同,矩阵再扩大亦是如此。
并且可以看出矩阵的全部信息只和第一行有关,恰好第一行就是数组 a a ,所以实际上这是一个(异或卷积)。
所以我们可以将问题转换成:给出向量 a a 和, fwt(a)⋅fwt(x)=fwt(b) f w t ( a ) ⋅ f w t ( x ) = f w t ( b ) ,求原向量 x x 。
那么我们就可以做一次,做一次 fwt(b) f w t ( b ) ,然后 x[i]=b[i]a[i] x [ i ] = b [ i ] a [ i ] ,再做一次逆 fwt(x) f w t ( x ) 就好了啊。
代码
#include <cstdio>
typedef long long LL;
const int N = 262150, p = 1e9+7;
LL a[N], b[N], x[N], n, inv2;
void fwt(LL *a) {
for (int i = 1; 1 << i <= n; i++) {
for (int j = 0; j < n; j += 1 << i) {
for (int k = 0; k < 1 << (i - 1); k++) {
LL x = a[j + k];
LL y = a[j + k + (1 << (i - 1))];
a[j + k] = (x + y) % p;
a[j + k + (1 << (i - 1))] = (x + p - y) % p;
}
}
}
}
void fwt(LL *a,int t) {
for (int i = 1; i < n; i <<= 1) {
for (int j = 0; j < n; j += (i << 1))
for (int k = j; k < i + j; k++) {
LL x = a[k], y = a[k + i];
a[k] = (x + y) % p, a[k + i] = (x - y + p) % p;
if (t)a[k] = a[k] * inv2 % p, a[k + i] = a[k + i] * inv2 % p;
}
}
}
LL Pow(LL a,LL n) {
LL ans = 1;
while (n) {
if (n & 1) ans = a * ans % p;
a = a * a % p;
n >>= 1;
}
return ans % p;
}
int main() {
scanf("%lld", &n);
inv2 = Pow(2, p - 2);
for (int i = 0; i < n; ++i)
scanf("%lld", a + i);
for (int i = 0; i < n; ++i)
scanf("%lld", b + i);
fwt(a);
fwt(b);
for (int i = 0; i < n; ++i) {
x[i] = b[i] * Pow(a[i], p - 2) % p;
}
fwt(x, 1);//逆fwt
for (int i = 0; i < n; ++i)
printf("%lld\n", x[i]);
// 实际上我们如果要算逆fwt也可以这样求
// for (int i = 0; i < n; ++i)
// printf("%lld\n", x[i] * Pow(n, p - 2) % p);
return 0;
}