題意
次多項式模意義下多點求值。
分析
可以直接上的多項式多點求值(不可能的)。
首先,可以取。
注意到,DFT的過程本身就是特殊的多點求值,對應的橫座標分別是,其中是次單位根。在NTT中,模意義下次單位根取的是
其中是的一個原根。如果我們直接對多項式做DFT,就可以得到到中,離散對數是的倍數的數的點值。注意到
如果我們構造新多項式的次項係數爲,求出來的點值,對應的就是原多項式中的點值。那麼就把求離散對數爲的數的點值轉化爲了求新多項式中離散對數爲的數的點值,直接套用上面的方法。同理離散對數爲的數的點值也可以這麼做。
總共只需要做三次DFT。注意當時取值爲。
代碼
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 300005;
const int MOD = 786433;
const int g = 10;
int n, a[N], b[N], c[N], rev[N], L, ans[MOD];
void pre()
{
int lg = 18; L = 1 << 18;
for (int i = 0; i < L; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));
}
int ksm(int x, int y)
{
int ans = 1;
while (y)
{
if (y & 1) ans = (LL)ans * x % MOD;
x = (LL)x * x % MOD; y >>= 1;
}
return ans;
}
void NTT(int * a)
{
for (int i = 0; i < N; i++) if (i < rev[i]) swap(a[i], a[rev[i]]);
for (int i = 1; i < L; i <<= 1)
{
int wn = ksm(g, (MOD - 1) / i / 2);
for (int j = 0; j < L; j += (i << 1))
{
int w = 1;
for (int k = 0; k < i; k++)
{
int u = a[j + k], v = (LL)a[j + k + i] * w % MOD;
a[j + k] = (u + v) % MOD; a[j + k + i] = (u + MOD - v) % MOD;
w = (LL)w * wn % MOD;
}
}
}
}
int main()
{
scanf("%d", &n);
for (int i = 0; i <= n; i++) scanf("%d", &a[i]);
ans[0] = a[0];
pre();
for (int i = 0; i <= n; i++) b[i] = (LL)a[i] * ksm(g, i) % MOD, c[i] = (LL)a[i] * ksm(g, i * 2) % MOD;
NTT(a); NTT(b); NTT(c);
int t1 = 1, t2 = g, t3 = (LL)g * g % MOD, p = (LL)t3 * g % MOD;
for (int i = 0; i < L; i++)
{
ans[t1] = a[i]; ans[t2] = b[i]; ans[t3] = c[i];
t1 = (LL)t1 * p % MOD;
t2 = (LL)t2 * p % MOD;
t3 = (LL)t3 * p % MOD;
}
int q; scanf("%d", &q);
while (q--)
{
int x; scanf("%d", &x);
printf("%d\n", ans[x]);
}
return 0;
}