📌  相关文章
📜  程序生成具有两个给定数组的卷积的数组

📅  最后修改于: 2021-05-17 19:00:05             🧑  作者: Mango

给定分别由NM个整数组成的两个数组A []B [] ,任务是构造一个大小为(N + M – 1)的卷积数组C []

注意:如果任何索引的值变得非常大,则将其打印为998244353模

例子:

天真的方法:在卷积数组中,每个项C [i + j] =(a [i] * b [j])%998244353 。因此,最简单的方法是使用两个嵌套循环对数组A []B []进行迭代,以找到生成的卷积数组C []

下面是上述方法的实现:

C++
// C++ program for the above approach
#include 
using namespace std;
constexpr int MOD = 998244353;
 
// Function to generate a convolution
// array of two given arrays
void findConvolution(const vector& a,
                     const vector& b)
{
    // Stores the size of arrays
    int n = a.size(), m = b.size();
 
    // Stores the final array
    vector c(n + m - 1);
 
    // Traver the two given arrays
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
           
              // Update the convolution array
            c[i + j] += 1LL*(a[i] * b[j]) % MOD;
        }
    }
 
    // Print the convolution array c[]
    for (int k = 0; k < c.size(); ++k) {
        c[k] %= MOD;
        cout << c[k] << " ";
    }
}
 
// Driver Code
int main()
{
    vector A = { 1, 2, 3, 4 };
    vector B = { 5, 6, 7, 8, 9 };
   
    findConvolution(A, B);
 
    return 0;
}


Java
// Java program for the above approach
import java.util.*;
 
class GFG{
 
static int MOD = 998244353;
 
// Function to generate a convolution
// array of two given arrays
static void findConvolution(int[] a,
                            int[] b)
{
     
    // Stores the size of arrays
    int n = a.length, m = b.length;
 
    // Stores the final array
    int[] c = new int[(n + m - 1)];
 
    // Traver the two given arrays
    for(int i = 0; i < n; ++i)
    {
        for(int j = 0; j < m; ++j)
        {
             
            // Update the convolution array
            c[i + j] += (a[i] * b[j]) % MOD;
        }
    }
 
    // Print the convolution array c[]
    for(int k = 0; k < c.length; ++k)
    {
        c[k] %= MOD;
        System.out.print(c[k] + " ");
    }
}
 
// Driver Code
public static void main(String args[])
{
    int[] A = { 1, 2, 3, 4 };
    int[] B = { 5, 6, 7, 8, 9 };
   
    findConvolution(A, B);}
}
 
// This code is contributed by souravghosh0416


Python3
# Python3 program for the above approach
MOD = 998244353
 
# Function to generate a convolution
# array of two given arrays
def findConvolution(a, b):
     
    global MOD
     
    # Stores the size of arrays
    n, m = len(a), len(b)
 
    # Stores the final array
    c = [0] * (n + m - 1)
 
    # Traver the two given arrays
    for i in range(n):
        for j in range(m):
             
            # Update the convolution array
            c[i + j] += (a[i] * b[j]) % MOD
 
    # Print the convolution array c[]
    for k in range(len(c)):
        c[k] %= MOD
        print(c[k], end = " ")
 
# Driver Code
if __name__ == '__main__':
     
    A = [1, 2, 3, 4]
    B = [5, 6, 7, 8, 9]
     
    findConvolution(A, B)
 
# This code is contributed by mohit kumar 29


C#
// C# program for the above approach
using System;
 
class GFG
{
 static int MOD = 998244353;
 
// Function to generate a convolution
// array of two given arrays
static void findConvolution(int[] a,
                    int[] b)
{
   
    // Stores the size of arrays
    int n = a.Length, m = b.Length;
 
    // Stores the final array
    int[] c = new int[(n + m - 1)];
 
    // Traver the two given arrays
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
           
              // Update the convolution array
            c[i + j] += (a[i] * b[j]) % MOD;
        }
    }
 
    // Print the convolution array c[]
    for (int k = 0; k < c.Length; ++k) {
        c[k] %= MOD;
        Console.Write(c[k] + " ");
    }
}
 
// Driver Code
public static void Main(String[] args)
{
    int[] A = { 1, 2, 3, 4 };
    int[] B = { 5, 6, 7, 8, 9 };
   
    findConvolution(A, B);
}
}
 
// This code is contributed by code_hunt.


C++
// C++ program for the above approach
#include 
using namespace std;
 
#define ll long long
 
const ll mod = 998244353, maxn = 3e6;
ll a[maxn], b[maxn];
 
// Iterative FFT function to compute
// the DFT of given coefficient vector
void fft(ll w0, ll n, ll* a)
{
    // Do bit reversal of the given array
    for (ll i = 0, j = 0; i < n; i++) {
 
        // Swap a[i] and a[j]
        if (i < j)
            swap(a[i], a[j]);
 
        // Right Shift N by 1
        ll bit = n >> 1;
 
        for (; j & bit; bit >>= 1)
            j ^= bit;
        j ^= bit;
    }
 
    // Perform the iterative FFT
    for (ll len = 2; len <= n; len <<= 1) {
 
        ll wlen = w0;
        for (ll aux = n; aux > len; aux >>= 1) {
            wlen = wlen * wlen % mod;
        }
 
        for (ll bat = 0; bat + len <= n; bat += len) {
 
            for (ll i = bat, w = 1; i < bat + len / 2;
                 i++, w = w * wlen % mod) {
 
                ll u = a[i], v = w * a[i + len / 2] % mod;
 
                // Update the value of a[i]
                a[i] = (u + v) % mod,
 
                // Update the value
                // of a[i + len/2]
                    a[i + len / 2]
                    = ((u - v) % mod + mod) % mod;
            }
        }
    }
}
 
// Function to find (a ^ x) % mod
ll binpow(ll a, ll x)
{
    // Stores the result of a ^ x
    ll ans = 1;
 
    // Iterate over the value of x
    for (; x; x /= 2, a = a * a % mod) {
 
        // If x is odd
        if (x & 1)
            ans = ans * a % mod;
    }
 
    // Return the resultant value
    return ans;
}
 
// Function to find the
// inverse of a % mod
ll inv(ll a) { return binpow(a, mod - 2); }
 
// Function to find the
// convolution of two arrays
void findConvolution(ll a[], ll b[], ll n, ll m)
{
    // Stores the first power of 2
    // greater than or equal to n + m
    ll _n = 1ll << 64 - __builtin_clzll(n + m);
 
    // Stores the primitive root
    ll w = 15311432;
    for (ll aux = 1 << 23; aux > _n; aux >>= 1)
        w = w * w % mod;
 
    // Convert arrays a[] and
    // b[] to point value form
    fft(w, _n, a);
    fft(w, _n, b);
 
    // Perform multiplication
    for (ll i = 0; i < _n; i++)
        a[i] = a[i] * b[i] % mod;
 
    // Perform inverse fft to
    // recover final array
    fft(inv(w), _n, a);
    for (ll i = 0; i < _n; i++)
        a[i] = a[i] * inv(_n) % mod;
 
    // Print the convolution
    for (ll i = 0; i < n + m - 1; i++)
        cout << a[i] << " ";
}
 
// Driver Code
int main()
{
    // Given size of the arrays
    ll N = 4, M = 5;
 
    // Fill the arrays
    for (ll i = 0; i < N; i++)
        a[i] = i + 1;
 
    for (ll i = 0; i < M; i++)
        b[i] = 5 + i;
 
    findConvolution(a, b, N, M);
 
    return 0;
}


输出:
5 16 34 60 70 70 59 36

时间复杂度: O(N * M)
辅助空间: O(N + M)

高效的方法:为了优化上述方法,其思想是使用类似于数论乘法的快速傅立叶变换(FFT)的数论变换( NTT ),它可以在模运算下工作。可以通过使用相同的迭代FFT概念在给定阵列上执行NTT来解决该问题,因为在模块化算术中,第N个单位具有相同的属性。

下面是上述方法的实现:

C++

// C++ program for the above approach
#include 
using namespace std;
 
#define ll long long
 
const ll mod = 998244353, maxn = 3e6;
ll a[maxn], b[maxn];
 
// Iterative FFT function to compute
// the DFT of given coefficient vector
void fft(ll w0, ll n, ll* a)
{
    // Do bit reversal of the given array
    for (ll i = 0, j = 0; i < n; i++) {
 
        // Swap a[i] and a[j]
        if (i < j)
            swap(a[i], a[j]);
 
        // Right Shift N by 1
        ll bit = n >> 1;
 
        for (; j & bit; bit >>= 1)
            j ^= bit;
        j ^= bit;
    }
 
    // Perform the iterative FFT
    for (ll len = 2; len <= n; len <<= 1) {
 
        ll wlen = w0;
        for (ll aux = n; aux > len; aux >>= 1) {
            wlen = wlen * wlen % mod;
        }
 
        for (ll bat = 0; bat + len <= n; bat += len) {
 
            for (ll i = bat, w = 1; i < bat + len / 2;
                 i++, w = w * wlen % mod) {
 
                ll u = a[i], v = w * a[i + len / 2] % mod;
 
                // Update the value of a[i]
                a[i] = (u + v) % mod,
 
                // Update the value
                // of a[i + len/2]
                    a[i + len / 2]
                    = ((u - v) % mod + mod) % mod;
            }
        }
    }
}
 
// Function to find (a ^ x) % mod
ll binpow(ll a, ll x)
{
    // Stores the result of a ^ x
    ll ans = 1;
 
    // Iterate over the value of x
    for (; x; x /= 2, a = a * a % mod) {
 
        // If x is odd
        if (x & 1)
            ans = ans * a % mod;
    }
 
    // Return the resultant value
    return ans;
}
 
// Function to find the
// inverse of a % mod
ll inv(ll a) { return binpow(a, mod - 2); }
 
// Function to find the
// convolution of two arrays
void findConvolution(ll a[], ll b[], ll n, ll m)
{
    // Stores the first power of 2
    // greater than or equal to n + m
    ll _n = 1ll << 64 - __builtin_clzll(n + m);
 
    // Stores the primitive root
    ll w = 15311432;
    for (ll aux = 1 << 23; aux > _n; aux >>= 1)
        w = w * w % mod;
 
    // Convert arrays a[] and
    // b[] to point value form
    fft(w, _n, a);
    fft(w, _n, b);
 
    // Perform multiplication
    for (ll i = 0; i < _n; i++)
        a[i] = a[i] * b[i] % mod;
 
    // Perform inverse fft to
    // recover final array
    fft(inv(w), _n, a);
    for (ll i = 0; i < _n; i++)
        a[i] = a[i] * inv(_n) % mod;
 
    // Print the convolution
    for (ll i = 0; i < n + m - 1; i++)
        cout << a[i] << " ";
}
 
// Driver Code
int main()
{
    // Given size of the arrays
    ll N = 4, M = 5;
 
    // Fill the arrays
    for (ll i = 0; i < N; i++)
        a[i] = i + 1;
 
    for (ll i = 0; i < M; i++)
        b[i] = 5 + i;
 
    findConvolution(a, b, N, M);
 
    return 0;
}
输出:
5 16 34 60 70 70 59 36

时间复杂度: O(N * log(N))
辅助空间: O(N + M)