Description:
1<=n<=8000,m<=57984且m是mo-1的約數
空間限制32MB,時間限制5s
題解:
首先思考一下怎麼做?
我們知道fft的本質是一個循環卷積,這道題要求,那麼可以利用這個特質而不管溢出,一開始對每一個點的序列進行dft,然後每次轉移就是把dft的序列乘起來,最後逆dft回去就好了。
因爲每個點一開始的序列只有一個位置有值,所以可以dft,即。
空間限制非常小,也就是我們不能把dft的序列存下來,考慮到dft後每一位完全獨立,所以可以先枚舉做哪一位,再在樹上dp。
還有一種方法,這是一個樹形依賴dp,考慮用樹鏈剖分節省空間,先做重兒子,把重兒子做完的數組的指針給當前點,然後做輕兒子,做完一個就合併,由於輕鏈+重鏈條數是log的,所以空間是的。
然後最後的問題是怎麼辦,此時的m依然是(mo-1)的約數,也就是存在單位複數根,那麼fft的性質依然可以用,只是不能用分治做fft,那麼不妨看一下式子:
把 dft成
那麼可以用一次卷積來完成這個dft的,實際上要做的是逆dft,差不多的。
注意常數優化。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x, B = y; i < B; i ++)
#define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
const int mo = 950009857;
ll ksm(ll x, ll y) {
ll s = 1;
for(; y; y /= 2, x = x * x % mo)
if(y & 1) s = s * x % mo;
return s;
}
const int N = 2e5 + 5;
ll a[N]; int r[N];
void dft(ll *a, int n, int F) {
ff(i, 0, n) {
r[i] = r[i / 2] / 2 + (i & 1) * (n / 2);
if(i < r[i]) swap(a[i], a[r[i]]);
}
for(int h = 1; h < n; h *= 2) {
ll wn = ksm(7, (mo - 1) / 2 / h);
for(int j = 0; j < n; j += 2 * h) {
ll b, *l = a + j, *r = a + j + h, w = 1;
ff(i, 0, h) {
b = *r * w, *r = (*l - b) % mo, *l = (*l + b) % mo;
w = w * wn % mo, l ++, r ++;
}
}
}
if(F == -1) {
reverse(a + 1, a + n);
ll v = ksm(n, mo - 2);
ff(i, 0, n) a[i] = (a[i] + mo) * v % mo;
}
}
void fft(ll *a, ll *b, int n) {
dft(a, n, 1); dft(b, n, 1);
ff(i, 0, n) a[i] = a[i] * b[i] % mo;
dft(a, n, -1);
}
int n, m, b[N], x, y;
int fi[N], to[N * 2], nt[N * 2], tot;
void link(int x, int y) {
nt[++ tot] = fi[x], to[tot] = y, fi[x] = tot;
}
int d[8005], d0, fa[8005];
void dg(int x) {
d[++ d0] = x;
for(int i = fi[x]; i; i = nt[i]) if(to[i] != fa[x])
fa[to[i]] = x, dg(to[i]);
}
int v[N], f[N];
ll w, aw[N];
ll s[N], s2[N * 2], s3[N * 2];
int c[N];
int main() {
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
scanf("%d %d", &n, &m);
w = ksm(7, (mo - 1) / m);
aw[0] = 1; fo(i, 1, m) aw[i] = aw[i - 1] * w % mo;
fo(i, 1, n) scanf("%d", &b[i]);
fo(i, 1, n - 1) {
scanf("%d %d", &x, &y);
link(x, y); link(y, x);
}
dg(1);
ff(j, 0, m) {
fo(i, 1, n) f[i] = aw[c[i]], c[i] = (c[i] + b[i] > m) ? (c[i] + b[i] - m) : (c[i] + b[i]);
fd(i, d0, 2) {
s[j] += f[d[i]];
f[d[i]] ++;
f[fa[d[i]]] = (ll) f[fa[d[i]]] * f[d[i]] % mo;
}
s[j] += f[1];
s[j] %= mo;
}
ll fw = ksm(w, m - 1);
ff(i, 0, 2 * m) s2[i] = ksm(w, (ll) i * (i - 1) / 2);
ff(i, 0, m) s[i] = s[i] * ksm(fw, (ll) i * (i - 1) / 2) % mo;
ff(i, 0, m) s3[m - i] = s[i];
int tp = 0;
while(1 << ++ tp <= 3 * m);
fft(s3, s2, 1 << tp);
ff(i, 0, m) s[i] = s3[i + m] * ksm(fw, (ll) i * (i - 1) / 2) % mo;
ff(i, 1, m / 2) swap(s[i], s[m - i]);
ff(i, 0, m) s[i] = s[i] * ksm(m, mo - 2) % mo;
ff(i, 0, m) pp("%lld ", (s[i] + mo) % mo);
}