牛客多校第九场 A (fwt-异或卷积)

127 篇文章 0 订阅
85 篇文章 2 订阅

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 2, let’s consider an n×n n × n matrix A A .

The index of A[i][j] and a[i] a [ i ] are numbered from 0 0 .
The element A[i][j] 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 n×n matrix, and x x and b 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 n=4, 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 a.

It is guaranteed that there is a unique solution x x for these equations.

Input

The first line contains an integer, which is n.
The second line contains n n integers, which are the array a.
The third line contains n n integers, which are the array b.

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 i-th(index from 0 0 ) line should contain x[i].
x[i] x [ i ] is an integer, and should satisfy 0<=x[i]<p 0 <= x [ i ] < p .

问题分析

首先,我们通过观察题目得到

A×x=b(modp) A × x = b ( mod p )

将矩阵 A A 展开
[a0a1a2a3a1a0a3a2a2a3a0a1a3a2a1a0]

我们可以发现这个矩阵左上角和右下角相同,左下角和右上角相同,矩阵再扩大亦是如此。
并且可以看出矩阵的全部信息只和第一行有关,恰好第一行就是数组 a a ,所以实际上这是一个fwt(异或卷积)。
所以我们可以将问题转换成:给出向量 a a b fwt(a)fwt(x)=fwt(b) f w t ( a ) ⋅ f w t ( x ) = f w t ( b ) ,求原向量 x x

那么我们就可以做一次fwt(a),做一次 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值