Solution -「LOCAL」 二進位制的世界
阿新 • • 發佈:2021-09-16
\(\mathcal{Description}\)
給定序列 \(\{a_n\}\) 和一個二元運算 \(\operatorname{op}\in\{\operatorname{and},\operatorname{or},\operatorname{xor}\}\),對於 \(i\in[2,n]\),求出 \(\max_{j\in[1,i)}\{a_i\operatorname{op} a_j\}\) 以及 \(|\arg\max_{j\in[1,i)}\{a_i\operatorname{op} a_j\}|\)。
\(n\le10^5\),\(a_i<2^{16}\)
\(\mathcal{Solution}\)
也許算是 Meet in Middle?從左到右線上更新可用的 \(a_j\) 資訊並求出對於當前 \(i\) 的答案,維護一個 \(f(u,v)\),表示選取的 \(a_j\) 的高八位是 \(u\) 且 \(a_i\) 的低八位是 \(v\) 時,低八位能得到的最大值以及方案數。那麼更新時,用當前 \(a_j\) 的低八位更新所有 \(f(u,i)\);查詢時列舉高八位選擇的值 \(i\),並用 \(f(i,v)\) 更新答案。最終複雜度為 \(\mathcal O(n\sqrt A)\)。
確實是比較巧妙的複雜度平衡,也是一個實用的 trick√
\(\mathcal{Code}\)
/*~Rainybunny~*/ #include <bits/stdc++.h> #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 std::pair<int, int> PII; #define fi first #define se second const int MAXN = 1e5, MAXSV = 1 << 8; int n, a[MAXN + 5]; char op[5]; PII f[MAXSV][MAXSV]; inline void update( const int x, const auto& opt ) { int h = x >> 8, l = x ^ h << 8; rep ( i, 0, MAXSV - 1 ) { int v = opt( i, l ); if ( f[h][i].fi < v ) f[h][i] = { v, 1 }; else if ( f[h][i].fi == v ) ++f[h][i].se; } } inline PII query( const int x, const auto& opt ) { int l = x & ( ( 1 << 8 ) - 1 ); PII ret( 0, 0 ); rep ( h, 0, MAXSV - 1 ) if ( f[h][l].se ) { int cur = opt( h, x >> 8 ) << 8 | f[h][l].fi; if ( ret.fi < cur ) ret = { cur, f[h][l].se }; else if ( ret.fi == cur ) ret.se += f[h][l].se; } return ret; } inline void solve( const auto& opt ) { update( a[1], opt ); rep ( i, 2, n ) { PII ans( query( a[i], opt ) ); printf( "%d %d\n", ans.fi, ans.se ), update( a[i], opt ); } } int main() { scanf( "%d %s", &n, op ); rep ( i, 1, n ) scanf( "%d", &a[i] ); if ( op[0] == 'x' ) { solve( []( const int u, const int v ) { return u ^ v; } ); } else if ( op[0] == 'a' ) { solve( []( const int u, const int v ) { return u & v; } ); } else { solve( []( const int u, const int v ) { return u | v; } ); } return 0; }