luogu P5641] [CSGRound2 pioneer of sagacity FFT

FFT good question.

First, we consider how to solve with a combination of mathematics. First put it concluded:

\(\displaystyle Ans[i]=\sum_{j=i}^ia_jC_{j+k-2}^{j-1}C_{i-j+k-1}^{i-j}\)

Give a simple proof:

Or a combination of mathematical old routine, we consider the contribution of each location to answer, the contribution is \ (a_j \ times \) contains \ (j \) location \ (1 \) stage and the number of sub-segments. For comprising \ (J \) position \ (1 \) stage and the number of sub-segments, from the \ (K \) to 1 as relatively cumbersome, we consider the \ (1 \) to \ (K \) operator. Because in the operator segment and sub-segment of our calculation is that it contains, in turn, is what we will \ ([j, j] \ ) of this subsection can be extended outward expansion of a number of sub-segments.

On the left is from \ (j \) and expandable to the right is from \ (j \) extended to i. From the left refinement \ (\ Times \) Total number of refinements to the right contains = refinement = \ (J \) position \ (1 \) stage and the number of sub-segments.

On the left to expand the number of how programs seek it? We can extend a total of k times, each can be extended in length [0, j-1], the final total length of extension j-1. Generating function used to represent the word is \ (\ displaystyle (\ sum_ { i = 0} ^ {j-1} x ^ i) ^ k \) a \ (x ^ {j-1 } \) coefficients.

Conclusion: n coefficients of this equation are views \ ({C_-n-K +. 1. 1-K} ^ {} \) (C is the number of combinations).

Proof: Recall \ (\ displaystyle \ sum_ {i = 0} ^ {j-1} x ^ i \) every multiplication meaning, found \ (\ displaystyle (\ sum_ { i = 0} ^ {j -1} x ^ i) ^ k \) the meaning is the n-th coefficient k after several programs consisting of n times, we can be regarded as n balls n, k is the k as a box, because the composition of n each "1" is the same, each polynomial are not the same, the same ball, different boxes, the program number is \ (C_ {n-1 + K-K-1} ^ {} \) .

I will not tell you that the above two paragraphs before I glued my blog

Therefore, the number of programs is extended to the left \ (J + K-C_ {^ {2}}. 1-J \) , the right side is the same token \ (C_ {ij + k- 1} ^ {ij} \) .

Set \ (A_j a_jC_ = {} J + K-2. 1-J ^ {} \) , \ (B_j = C_ {J + K-J. 1} ^ {} \) , we know into opinions

\(\displaystyle Ans[i]=\sum_{j=i}^iA_jB_{i-j}\).

\ (Ans = A * B \)

NTT click on it.

And so on, k is so big, how beg C?

K modulo the still large, we \ (C_n ^ m \) open \ (\ displaystyle C_n ^ m = \ frac {n!} {M! (Nm)!} = \ Frac {\ prod_ {i . 1-n-m + =}} ^ {n-I} {\ prod_. 1} {I = I ^ {m}} \) , and because \ (C_n ^ 0 = 1 \ ) then we can recursive composition it For details, please refer to the code.

#include<iostream>
#include<cstdio>
#define LL long long
#define DB double
using namespace std;
int n, k;
const int N = 400010, mod = 998244353, G = 3, Ginv = (mod + 1) / 3;
int r[N];
LL a[N], A[N], B[N], inv[N];
inline int read() 
{
    int res = 0; char ch = getchar(); bool XX = false;
    for (; !isdigit(ch); ch = getchar())(ch == '-') && (XX = true);
    for (; isdigit(ch); ch = getchar())res = (res << 3) + (res << 1) + (ch ^ 48);
    return XX ? -res : res;
}
inline LL ksm(LL a, LL b, LL mod) 
{
    LL res = 1;
    for (; b; b >>= 1, a = a * a % mod)
        if (b & 1)res = res * a % mod;
    return res;
}
inline LL mo(LL x) {return x >= mod ? x - mod : x;}
inline void NTT(LL *A, int lim, int opt) 
{
    for (int i = 0; i < lim; ++i)
        if (i < r[i])swap(A[i], A[r[i]]);
    int len, mid, j, k;
    LL wn, w, x, y;
    for (mid = 1; mid < lim; mid <<= 1) 
    {
        len = mid << 1;
        wn = ksm(opt == 1 ? G : Ginv, (mod - 1) / len, mod);
        for (j = 0; j < lim; j += len) 
        {
            w = 1;
            for (k = j; k < j + mid; ++k, w = w * wn % mod) 
            {
                x = A[k]; y = A[k + mid] * w % mod;
                A[k] = mo(x + y);
                A[k + mid] = mo(x - y + mod);
            }
        }
    }
    if (opt == 1)return;
    int ni = ksm(lim, mod - 2, mod);
    for (int i = 0; i < lim; ++i)A[i] = A[i] * ni % mod;
}
inline void MUL(LL *A, int n, LL *B, int m) 
{
    int lim = 1, i;
    while (lim < (n + m))lim <<= 1;
    for (i = 1; i < lim; ++i)
        r[i] = (r[i >> 1] >> 1) | ((i & 1) ? (lim >> 1) : 0);
    NTT(A, lim, 1); NTT(B, lim, 1);
    for (i = 0; i < lim; ++i)A[i] = A[i] * B[i] % mod;
    NTT(A, lim, -1);
}
void Write(int x, int opt) 
{
    if (opt && !x)putchar('0');
    if (!x)return;
    Write(x / 10, 0);
    putchar((x - x / 10 * 10) + '0');
}
signed main() 
{
    int i;
    cin >> n >> k;
    for (i = 1; i <= n; ++i)a[i] = read();
    inv[1] = 1;
    A[1] = 1; B[0] = 1; B[1] = k;
    for (i = 2; i <= n; ++i) 
    {
        inv[i] = mod - mod / i * inv[mod % i] % mod;
        A[i] = A[i - 1] * (i + k - 2) % mod * inv[i - 1] % mod;
        B[i] = B[i - 1] * (i + k - 1) % mod * inv[i] % mod;
    }
    for (i = 1; i <= n; ++i)A[i] = A[i] * a[i] % mod;
    MUL(A, n, B, n);
    for (i = 1; i <= n; ++i)Write(A[i], 1), putchar(' ');
    return 0;
}

Guess you like

Origin www.cnblogs.com/wljss/p/12031543.html
FFT