Bluestein's Algorithm

用下降幂搞搞事情

\[ \frac{m(m-1) + k(k+1) -(m-k)(m-k-1)}{2} \\ =\frac{m^2 - m + k^2 + k - m^2 - k^2 + 2mk - k + m}{2} \\ = mk \\ y_{m} = \sum_{k=0}^n A_{k}\omega^{mk}\\=\omega^{\frac{m(m-1)}{2}}\sum_{k=0}^n A_k\omega^{\frac{k(k+1)}{2}}\omega^{\frac{-(m-k)(m-k-1)}{2}} \]

后面是一个卷积形式,可以快速实现求 \(f(x),f(x^1), f(x^2) .. f(x^n)\) 以及循环卷积意义下的多项式快速幂。

例题 UOJ500 任意基DFT

观察发现

\[q_m = q_0x^m+\sum_{i=0}^{m-1} xy^i =(\frac{y}{x-1}+q_0)x^m-\frac{y}{x-1}\\ \]

​ 设 \(c = \frac{y}{x-1}\) ,那么有

\[f(q_m) = \sum_{i=0}^n a_i((c+q_0)x^m-c)^i \\ =\sum_{i=0}^n a_i\sum_{j=0}^i{i\choose j}(c+q_0)^jx^{mj}(-c)^{i-j} \\ =\sum_{i=0}^n(c+q_0)^ix^{mi}\sum_{j=i}^n{i \choose j}(-c)^{i-j}a_i \]

\(b_j = (c+q_0)^i \sum_{j=i}^n{i \choose j}(-c)^{i-j}a_i\) ,这是一个卷积形式,可以用一遍 \(\text{FFT}\) 求出所有的 \(b\) ,那么

\[f(q_m) = \sum_{i=0}^nb_i x^{mi} \]

再跑一遍 bluestein's 对 \(1-m\) 求解即可,注意用线性递推求幂次来优化常数。

code

/*program by mangoyang*/
#pragma GCC optimize("Ofast", "inline")
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
    int ch = 0, f = 0; x = 0;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    if(f) x = -x;
}
const int N = 1 << 21, mod = 998244353, G = 3;
int a[N], b[N], A[N], B[N], C[N], d[N], e[N], js[N], inv[N], n, q, q0, qx, qy;
inline void up(int &x, int y){
	x = x + y >= mod ? x + y - mod : x + y;
}
inline int Pow(int a, int b){
	int ans = 1;
	for(; b; b >>= 1, a = 1ll * a * a % mod)
		if(b & 1) ans = 1ll * ans * a % mod;
	return ans;
}
namespace poly{
	int rev[N], len, lg;
	inline void init(int lenth){
		for(len = 1, lg = 0; len <= lenth; len <<= 1, lg++);
		for(int i = 0; i < len; i++)
			rev[i] = (rev[i>>1] >> 1) | ((i & 1) << (lg - 1));
	}
	inline void dft(int *a, int sgn){
		for(int i = 0; i < len; i++)
			if(i < rev[i]) swap(a[i], a[rev[i]]);
		for(int k = 2; k <= len; k <<= 1){
			int w = Pow(G, (mod - 1) / k);
			if(sgn == -1) w = Pow(w, mod - 2);
			for(int i = 0, now; i < len; i += k){
				now = 1;
				for(int j = i; j < i + (k >> 1); j++){
					int x = a[j], y = 1ll * a[j+(k>>1)] * now % mod;
					a[j] = x + y >= mod ? x + y - mod : x + y;
					a[j+(k>>1)] = x - y < 0 ? x - y + mod : x - y;
					now = 1ll * now * w % mod;
				}
			}
		}
		if(sgn == -1){
			int x = Pow(len, mod - 2);
			for(int i = 0; i < len; i++) a[i] = 1ll * a[i] * x % mod;
		}
	}
}
int main(){
	read(n), read(q), js[0] = 1, inv[0] = 1;
	for(int i = 1; i <= n; i++){
		js[i] = 1ll * js[i-1] * i % mod;
		inv[i] = Pow(js[i], mod - 2);
	}
	for(int i = 0; i <= n; i++) read(a[i]);
	read(q0), read(qx), read(qy);
	int c = 1ll * qy * Pow(qx - 1, mod - 2) % mod;
	for(int i = 0, ss = 1; i <= n; i++){
		A[n-i] = 1ll * js[i] * a[i] % mod;
		B[i] = 1ll * inv[i] * ss % mod;
		ss = 1ll * ss * (mod - c) % mod;
	}
	poly::init(n + n + 1);
	poly::dft(A, 1), poly::dft(B, 1);
	for(int i = 0; i < poly::len; i++)
		C[i] = 1ll * A[i] * B[i] % mod;
	poly::dft(C, -1);
	for(int i = 0; i <= n; i++){
		b[i] = 1ll * C[n-i] * inv[i] % mod;
		b[i] = 1ll * b[i] * Pow(c + q0, i) % mod;
	}
	memset(A, 0, sizeof(A));
	memset(B, 0, sizeof(B));
	memset(C, 0, sizeof(C));
	d[0] = 1, e[0] = 1;
	int ix = Pow(qx, mod - 2);
	for(int i = 1, ss = 1, tt = 1; i <= n + q + 1; i++){
		ss = 1ll * qx * ss % mod;
		tt = 1ll * ix * tt % mod;
		d[i] = 1ll * d[i-1] * ss % mod;
		e[i] = 1ll * e[i-1] * tt % mod;
	}
	for(int i = 0; i <= n; i++)
		A[i] = 1ll * b[i] * d[i] % mod;
	for(int i = -n + 1; i <= q; i++)
		B[i+n] = i <= 0 ? e[abs(i)] : e[i-1];
	poly::init(n + n + q);
	poly::dft(A, 1), poly::dft(B, 1);
	for(int i = 0; i < poly::len; i++)
		C[i] = 1ll * A[i] * B[i] % mod;
	poly::dft(C, -1);
	int ans = 0;
	for(int i = 1; i <= q; i++)
		ans ^= 1ll * C[i+n] * d[i-1] % mod;
	cout << ans << endl;
	return 0;
}
posted @ 2020-05-29 20:21  Joyemang33  阅读(469)  评论(0编辑  收藏  举报