高速 Walsh-Hadamrd 変換. 高速フーリエ変換の亜種で FFT が $c[k] = \underset{i+j=k}{\mathrm{sum}} a[i] \times b[j]$ を満たす $c$ を求めるのに対し,
$c[k] = \underset{i \oplus j=k}{\mathrm{sum}} a[i] \times b[j]$ を満たす $c$ を求めるアルゴリズム(xor-convolution).
xor 以外にも係数行列を少し変えれば and, or についても求めることが可能である.
時間計算量: $\O (n \log n)$
- #define MOD 1000000007
- inline int add(int x, int y)
- {
- return (x + y)%MOD;
- }
- inline int sub(int x, int y)
- {
- return (x+MOD-y)%MOD;
- }
- inline int mul(int x, int y)
- {
- return (long long)x*y%MOD;
- }
- inline int mod_pow(int a, int b)
- {
- int res = 1;
- while(b){
- if(b & 1){
- res = mul(res, a);
- }
- a = mul(a, a);
- b >>= 1;
- }
- return res;
- }
- // xor convolution
- void fwht(vector<int>& poly, bool rev=false){
- int n = (int)poly.size();
- for(int i = 1; i < n; i *= 2){
- for(int j = 0; j < i; j++){
- for(int k = 0; k < n; k += i*2){
- int u = poly[j+k], v = poly[j+k+i];
- poly[j+k] = add(u, v);
- poly[j+k+i] = sub(u, v);
- }
- }
- }
- if(rev){
- int inv = mod_pow(n, MOD-2);
- for(int i = 0; i < n; i++){
- poly[i] = mul(poly[i], inv);
- }
- }
- }
- // or convolution
- // void fwht(vector<int>& poly, bool rev=false){
- // int n = (int)poly.size();
- // for(int i = 1; i < n; i *= 2){
- // for(int j = 0; j < i; j++){
- // for(int k = 0; k < n; k += i*2){
- // if(rev){
- // poly[j+k+i] = sub(poly[j+k+i], poly[j+k]);
- // }else{
- // poly[j+k+i] = add(poly[j+k+i], poly[j+k]);
- // }
- // }
- // }
- // }
- // }
- // and convolution
- // void fwht(vector<int>& poly, bool rev=false){
- // int n = (int)poly.size();
- // for(int i = 1; i < n; i *= 2){
- // for(int j = 0; j < i; j++){
- // for(int k = 0; k < n; k += i*2){
- // int u = poly[j+k], v = poly[j+k+i];
- // if(rev){
- // poly[j+k] = sub(v, u);
- // poly[j+k+i] = u;
- // }else{
- // poly[j+k] = v;
- // poly[j+k+i] = add(u, v);
- // }
- // }
- // }
- // }
- // }
- vector<int> mul(vector<int> a, vector<int> b){
- int sm = (int)a.size() + (int)b.size() - 1, size_ = 1;
- while(size_ < sm) size_ *= 2;
- a.resize(size_, 0), b.resize(size_, 0);
- fwht(a), fwht(b);
- for(int i = 0; i < size_; i++){
- a[i] = mul(a[i], b[i]);
- }
- fwht(a, true);
- a.resize(sm);
- return a;
- }
yosupo さんの library checker : Bitwise Xor Convolution
提出コード (xor convolution の verify)
yosupo さんの library checker : Bitwise And Convolution
提出コード (and convolution の verify)