// writer: w33z8kqrqk8zzzx33
#include <bits/stdc++.h>
using namespace std;
// begin fast read template by CYJian (source: https://www.luogu.com.cn/paste/i11c3ppx)
namespace io {
const int __SIZE = (1 << 21) + 1;
char ibuf[__SIZE], *iS, *iT, obuf[__SIZE], *oS = obuf, *oT = oS + __SIZE - 1, __c, qu[55]; int __f, qr, _eof;
#define Gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, __SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
inline void flush () { fwrite (obuf, 1, oS - obuf, stdout), oS = obuf; }
inline void gc (char &x) { x = Gc(); }
inline void pc (char x) { *oS ++ = x; if (oS == oT) flush (); }
inline void pstr (const char *s) { int __len = strlen(s); for (__f = 0; __f < __len; ++__f) pc (s[__f]); }
inline void gstr (char *s) { for(__c = Gc(); __c < 32 || __c > 126 || __c == ' ';) __c = Gc();
for(; __c > 31 && __c < 127 && __c != ' '; ++s, __c = Gc()) *s = __c; *s = 0; }
template <class I> inline bool gi (I &x) { _eof = 0;
for (__f = 1, __c = Gc(); (__c < '0' || __c > '9') && !_eof; __c = Gc()) { if (__c == '-') __f = -1; _eof |= __c == EOF; }
for (x = 0; __c <= '9' && __c >= '0' && !_eof; __c = Gc()) x = x * 10 + (__c & 15), _eof |= __c == EOF; x *= __f; return !_eof; }
template <class I> inline void print (I x) { if (!x) pc ('0'); if (x < 0) pc ('-'), x = -x;
while (x) qu[++ qr] = x % 10 + '0', x /= 10; while (qr) pc (qu[qr --]); }
struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
} using io::pc; using io::gc; using io::pstr; using io::gstr; using io::gi; using io::print;
// end fast read template by CYJian
#define iter(i, a, b) for(int i=(a); i<(b); i++)
#define rep(i, a) iter(i, 0, a)
#define rep1(i, a) iter(i, 1, (a)+1)
#define log(a) cerr<<"\033[32m[DEBUG] "<<#a<<'='<<(a)<<" @ line "<<__LINE__<<"\033[0m"<<endl
#define all(a) a.begin(), a.end()
#define fi first
#define se second
#define pb push_back
#define mp make_pair
using ll=long long;
using pii=pair<int, int>;
//#define int ll
const int MOD = 998244353;
int qpow(int b, int e) {
int ans = 1;
while(e) {
if(e & 1) ans = 1ll * ans * b % MOD;
b = 1ll * b * b % MOD;
e >>= 1;
}
return ans;
}
namespace poly {
const int MOD = 998244353;
const int NTTG = 3;
int rev[1<<23];
int minv[1<<23];
int w[23][2][1<<23];
int qpow(int b, int e) {
int re=1;
while(e){
if(e&1)re=1ll*re*b%MOD;
b=1ll*b*b%MOD;e>>=1;
}
return re;
}
void constructrev(int n) {
for(int i=1, j=0; i < n; i++) {
int bit=n>>1;
for(;j&bit;bit>>=1)j^=bit;
j^=bit; rev[i] = j;
}
}
void constructroot(int n) {
minv[1] = 1;
iter(i, 2, n+1)
minv[i]=1ll*(MOD-MOD/i)*minv[MOD%i]%MOD;
for(int l=1; (1<<l)<=n; l++)
rep(inv, 2) {
int re = inv?qpow(minv[NTTG],(MOD-1)>>l):qpow(NTTG,(MOD-1)>>l);
w[l][inv][0] = 1;
rep1(i,(1<<(l-1))-1) w[l][inv][i] = 1ll*w[l][inv][i-1]*re%MOD;
}
}
void ntt(int *v, int n, bool inv) {
rep(i, n) if(i < rev[i]) swap(v[i], v[rev[i]]);
for(int l=1;(1<<l)<=n;l++)
for(int i=0;i<n;i+=(1<<l)) {
int p=i+(1<<(l-1));
iter(j, i, p) {
int a=v[j],b=1ll*v[j+(1<<(l-1))]*w[l][inv][j-i]%MOD;
v[j]=(a+b>=MOD?a+b-MOD:a+b);
v[j+(1<<(l-1))]=(a<b?a+MOD-b:a-b);
}
}
if(inv) rep(i, n) v[i] = 1ll*v[i]*minv[n]%MOD;
}
void mult(int *a, int as, int *b, int bs, int *o, bool construct, bool clean = 0, int thr = 10000000) {
int n = as+bs-1;
while(n - (n & (-n))) n += (n & (-n));
if(construct) constructroot(n);
constructrev(n);
ntt(a, n, 0); ntt(b, n, 0);
rep(i, n) o[i] = 1ll*a[i]*b[i]%MOD;
ntt(o, n, 1);
iter(i, thr, n) o[i] = 0;
if(clean) rep(i, n) a[i] = b[i] = 0;
}
}
int Av[1<<23];
int Bv[1<<23];
int res[1<<23];
signed main() {
ios_base::sync_with_stdio(false); cin.tie(0);
int n, c, m; gi(n), gi(c), gi(m);
int th = max(m, n);
int ic = qpow(c, MOD-2);
rep(i, 2*th) Av[i] = qpow(c, 1ll * i * (i-1) / 2 % (MOD - 1));
rep(i, n) {
int s; gi(s);
Bv[th-1-i] = 1ll * s * qpow(ic, 1ll * i * (i-1) / 2 % (MOD-1)) % MOD;
}
poly::mult(Av, 2*th, Bv, 2*th, res, 1);
rep(i, m) print(1ll * res[th-1+i] * qpow(ic, 1ll * i * (i-1) / 2 % (MOD-1)) % MOD), pc(' ');
}
Thanks, I didn't really understand the trick before! By the way:
1) Maybe you want to replace $$$x$$$ with $$$c$$$ in all equations since we're trying to find $$$P(c^0), P(c^1), \dots, P(c^m)$$$? I got a bit confused when I saw $$$x^{\binom{i+j}{2}}$$$ and I didn't understand why it wasn't a polynomial of huge degree.
2) Just as a sidenote, a graphical proof of $$$ij = \binom{i+j}{2} - \binom{i}{2} - \binom{j}{2}$$$. Each triangle of side $$$x$$$ contains $$$\binom{x+1}{2}$$$ items. Now, we get that
rectangle = huge triangle - '%' triangle - '@' triangle
:1) Thank you for the suggestion! It is a bit unclear, and I have changed all of the incorrect $$$x$$$ es.
2) I didn't think of this interesting geometrical interpretation. This is a cool different and simpler method of proving the identity :)
Maybe someone wants another proof for $$${i+j \choose 2} = {i \choose 2} + {j \choose 2} + ij$$$.
LHS: $$${i+j \choose 2}$$$ counts the number of unordered pairs we can pick from $$$\{1, 2, \dots, i+j\}$$$.
RHS: $$${i \choose 2}$$$ counts the number of unordered pairs which only use numbers from $$$A = \{1, 2, \dots, i\}$$$. $$${j \choose 2}$$$ counts the number of unordered pairs which only use numbers from $$$B = \{i+1, i+2 \dots, i+j\}$$$. Now the only pairs we haven't counted yet are of the form $$$\{ x, y \}$$$ where $$$x \in A \wedge y \in B$$$. $$$A$$$ and $$$B$$$ are disjoint so this is just $$$|A| \cdot |B| = ij$$$.