\(\mathcal{Description}\)
Link.
给定两个不超过 \(2^n-1\) 次的多项式 \(A,B\),对于第 \(i\in[0,n)\) 个二进制位,定义任意一个二元加法 \(\oplus_i:\{0,1\}\times\{0,1\}\rightarrow\{0,1\}\),而对于两个整数 \(u,v\in[0,2^n)\),定义 \(u\oplus v=\sum_{i=0}^{n-1}(u_i\oplus_i v_i)2^i\)。求 \(A,B\) 的 \(\oplus\) 卷积,保证答案任意系数不超过 \(2^{63}-1\)。
\(\mathcal{Solution}\)
可以看出这个问题不弱于 FWT,所以我们大概需要根据 FWT 的思路,来 DIY 一个变换。
在 FWT 的框架下,枚举每个二进制位,对 \(16\) 种不同的加法分别构造各自的变换方式,构造时只需要考虑 \((a_0+a_1x)\) 与 \((b_0+b_1x)\) 的卷积,使得这个卷积合法即可。
复杂度 \(\mathcal O(2^nn)\)。
\(\mathcal{Code}\)
不要用 switch
!不要用 switch
!不要用 switch
!这个语法真的离谱。
啊……极少地在代码里爆了粗口,以记录我分类讨论加上被 switch
弄傻的愉悦!(
/*~Rainybunny~*/
#include <cstdio>
#include <cassert>
#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )
typedef long long LL;
const int MAXN = 18, MAXL = 1 << MAXN;
int n;
LL a[MAXL + 5], b[MAXL + 5];
char op[MAXN + 5][4];
inline int type( const char* o ) {
int ret = 0;
per ( i, 3, 0 ) ret = ret << 1 | ( o[i] ^ '0' );
return ret;
}
inline void fuckin_wa_tle( const int len, LL* u, const int tp ) {
// { -1: first item, 0: result, 1: second item }.
#define swp( a, b ) void( a ^= b ^= a ^= b )
for ( int i = 0, stp = 1; stp < len; ++i, stp <<= 1 ) {
for ( int j = 0; j < len; j += stp << 1 ) {
rep ( k, j, j + stp - 1 ) {
LL &p = u[k], &q = u[k + stp];
switch ( type( op[i] ) ) {
// what fuckin stupid grammar??? I'll never `switch` again.
case 0:
if ( !~tp ) p += q, q = 0;
else if ( tp ) p += q, q = 0;
break;
case 1:
if ( !~tp ) swp( p, q ), p += q;
else if ( tp ) swp( p, q ), p += q;
else p -= q;
break;
case 2:
if ( !~tp ) swp( p, q ), p += q;
else if ( tp ) p += q;
else p -= q;
break;
case 3:
if ( !~tp ) swp( p, q );
else if ( tp ) p = q = p + q;
break;
case 4:
if ( !~tp ) p += q;
else if ( tp ) swp( p, q ), p += q;
else p -= q;
break;
case 5:
if ( !~tp ) p = q = p + q;
else if ( tp == 1 ) swp( p, q );
break;
case 6:
p += q, q = p - 2 * q;
if ( !tp ) {
assert( !( p % 2 ) && !( q % 2 ) );
p /= 2, q /= 2;
}
break;
case 7:
if ( !~tp ) swp( p, q ), q += p;
else if ( tp ) swp( p, q ), q += p;
else q -= p;
break;
case 8:
if ( !~tp ) p += q;
else if ( tp ) p += q;
else p -= q;
break;
case 9:
q += p, p = q - 2 * p;
if ( !tp ) {
assert( !( p % 2 ) && !( q % 2 ) );
p /= 2, q /= 2;
}
break;
case 10:
if ( !~tp ) p = q = p + q;
break;
case 11:
if ( !~tp ) swp( p, q ), q += p;
else if ( tp ) q += p;
else q -= p;
break;
case 12:
if ( tp == 1 ) p = q = p + q;
break;
case 13:
if ( !~tp ) q += p;
else if ( tp ) swp( p, q ), q += p;
else q -= p;
break;
case 14:
if ( !~tp ) q += p;
else if ( tp ) q += p;
else q -= p;
break;
case 15:
if ( !~tp ) q += p, p = 0;
else if ( tp ) q += p, p = 0;
break;
default: assert( false );
}
}
}
}
#undef swp
}
int main() {
scanf( "%d", &n );
rep ( i, 0, n - 1 ) scanf( "%s", op[i] );
rep ( i, 0, ( 1 << n ) - 1 ) scanf( "%lld", &a[i] );
rep ( i, 0, ( 1 << n ) - 1 ) scanf( "%lld", &b[i] );
fuckin_wa_tle( 1 << n, a, -1 ), fuckin_wa_tle( 1 << n, b, 1 );
rep ( i, 0, ( 1 << n ) - 1 ) a[i] *= b[i];
fuckin_wa_tle( 1 << n, a, 0 );
rep ( i, 0, ( 1 << n ) - 1 ) {
printf( "%lld%c", a[i], i < repi ? ' ' : '\n' );
}
return 0;
}