solution
考虑一种计数的方案,
g
(
n
)
=
∑
x
+
y
=
n
C
(
n
,
x
)
⋅
3
x
y
g(n) = \sum_{x+y=n} C(n,x) \cdot 3^{xy}
g(n)=∑x+y=nC(n,x)⋅3xy
x,y分别是左右的点数,3的几次方意思是黑 / 白 / 没有。
容易发现,对于一个有k个连通块的真正的黑白图,会在g(n)中贡献 2 k 2^k 2k次。
设 f ( n ) f(n) f(n)表示大小为n的连通黑白图数量。
这种带标号的东西,通常不考虑ogf而考虑egf。
设F,G分别是f,g的efg。
考虑答案的egf是什么。容易发现就是
e
F
e^F
eF。式子自己展开一下就知道了。
然后"正好"
G
(
x
)
=
e
2
F
(
x
)
G(x) = e^{2F(x)}
G(x)=e2F(x)。
那么求出G,开个根就是F了。
顺便复习了一波多项式求逆和开根。
开根
设
T
2
(
x
)
=
A
(
x
)
(
m
o
d
x
n
)
T^2(x) = A(x) (mod x^n)
T2(x)=A(x)(modxn)
G
2
(
x
)
=
A
(
x
)
(
m
o
d
x
2
n
)
G^2(x) = A(x) (mod x^{2n})
G2(x)=A(x)(modx2n)
容易发现,
T
(
x
)
=
G
(
x
)
(
m
o
d
x
n
)
T(x) = G(x) (mod x^n)
T(x)=G(x)(modxn)
G
2
(
x
)
+
T
2
(
x
)
−
2
T
(
x
)
G
(
x
)
=
0
(
m
o
d
x
2
n
)
G^2(x) + T^2(x) - 2T(x)G(x)=0(mod x^{2n})
G2(x)+T2(x)−2T(x)G(x)=0(modx2n)
A
(
x
)
+
T
2
(
x
)
−
2
T
(
x
)
G
(
x
)
=
0
(
m
o
d
x
2
n
)
A(x)+ T^2(x) - 2T(x)G(x)=0(mod x^{2n})
A(x)+T2(x)−2T(x)G(x)=0(modx2n)
就可以求出G了。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define clear(st,ed) (memset(&st,0,sizeof(st) * ((&ed)-(&st))))
#define copy(tg,st,ed) (memcpy(&tg,&st,(&ed)-(&st)))
using namespace std;
typedef long long ll;
const int N = 1.5e6, mo = 998244353,inv3 = (mo + 1) / 3, inv2 = (mo + 1) / 2;
ll q,n=1e5;
ll o;
ll g[N],jc[N],njc[N],h[N],w[N],iw[N],M;
ll ksm(ll x,ll y) {
ll ret = 1;
for (; y; y>>=1) {
if (y & 1) ret = ret * x % mo;
x = x * x % mo;
}
return ret;
}
void dft(ll *a,ll sz,int sig) {
for (int i = 1; i < sz; i++)
h[i] = (h[i>>1]>>1) + (i & 1) * (sz >> 1);
for (int i = 0; i < sz; i++) if (h[i] < i) swap(a[i],a[h[i]]);
for (int m = 1, g = 1; m < sz; m<<=1,g++) {
for (int i = 0; i < sz; i+=m<<1) {
for (int j = 0; j < m; j++) {
ll A = a[i+j+m] * (sig == 1 ? w[(M>>g) * j] : iw[(M>>g) * j]) % mo;
a[i+j+m] = (a[i+j] + mo - A) % mo;
a[i+j] = (a[i+j] + A) % mo;
}
}
}
if (sig == -1) {
ll ny = ksm(sz, mo - 2);
for (int i = 0; i < sz; i++) a[i] = a[i] * ny % mo;
}
}
ll G[N],tmp[N];
void inv(ll *G,ll *ori,int sz) {
if (sz == 1) {
G[0] = ksm(ori[0], mo - 2);
return;
}
int csj = sz << 1;
inv(G,ori,sz>>1);
clear(G[sz>>1],G[csj]);
dft(G,csj,1);
for (int i = 0; i < csj; i++)
tmp[i] = i < sz ? ori[i] : 0;
dft(tmp,csj,1);
for (int i = 0; i < csj; i++)
G[i] = G[i] * (2 - tmp[i] * G[i] % mo) % mo;
dft(G,csj,-1);
clear(G[sz],G[csj]);
}
ll invg[N];
void sqrt(ll *G,ll *ori,int sz) {
if (sz == 1) {
G[0] = 1; return;
}
int csj = sz << 1;
sqrt(G, ori, sz >> 1);
clear(invg[0],invg[csj]);
inv(invg, G, sz);
dft(G, csj, 1);
dft(invg, csj, 1);
for (int i = 0; i < csj; i++)
tmp[i] = i < sz ? ori[i] : 0;
dft(tmp, csj, 1);
for (int i = 0; i < csj; i++)
G[i] = (G[i] * G[i] + tmp[i]) % mo * invg[i] % mo * inv2 % mo;
dft(G, csj, -1);
clear(G[sz],G[csj]);
}
void init() {
M = 262144 * 2;
ll ww = ksm(3, (mo - 1) / M);
iw[0] = w[0] = 1;
for (int i = 1; i < M; i++) w[i] = w[i-1] * ww % mo;
ww = ksm(ww, mo - 2);
for (int i = 1; i < M; i++) iw[i] = iw[i-1] * ww % mo;
jc[0] = 1; for (int i = 1; i <= n; i++) jc[i] = jc[i-1] * i % mo;
njc[n] = ksm(jc[n], mo - 2);
for (int i = n - 1; ~i; i--) njc[i] = njc[i+1] * (i+1) % mo;
}
ll od[N],ev[N],mer[N],rr[N];
ll d[N];
void getg() {
for (ll i = 0; i <= n; i++) {
if (i & 1) {
od[i] = ksm(inv3, i * i >> 1) * njc[i] % mo;
} else {
ev[i] = ksm(inv3, i * i >> 1) * njc[i] % mo;
}
}
dft(od, 262144, 1); dft(ev, 262144, 1);
for (int i = 0; i < 262144; i++) {
mer[i] = (ev[i] * ev[i] % mo
+ 2 * ev[i] * od[i] % mo
+ od[i] * od[i] % mo * inv3 % mo) % mo;
}
dft(mer, 262144, -1);
for (ll i = 0; i <= n; i++) {
mer[i] = mer[i] * ksm(3, i * i >> 1) % mo;
}
}
int main() {
freopen("graph.in","r",stdin);
init();
cin>>q;
getg();
sqrt(rr, mer, 262144);
for (;q;q--){
int u; scanf("%d",&u);
printf("%lld\n",((jc[u] * rr[u] % mo) + mo) % mo);
}
}