Solution -「JOISC 2021」古老的機器
阿新 • • 發佈:2021-06-23
\(\mathcal{Description}\)
Link.
這是一道通訊題。
對於長度為一個 \(n\),僅包含字元 X
, Y
, Z
的字串 \(s\),將其中 \(n\) 個字元按任意順序刪去,定義刪除方案的權值為在子串 XYZ
中刪除 Y
的次數。實現兩個函式:
void Anna(int N, std::vector<char> S)
,獲取字串資訊,傳遞不超過 \(7\times10^4\) 個01
位用於通訊;void Bruno(int N, int L, std::vector<int> A)
,獲取通訊資訊,給出權值最大的刪除方案。
\(n\le10^5\)
\(\mathcal{Solution}\)
先看看怎麼求最大權值。考慮當前最左側 X
的位置 \(i\) 與最左側 Z
的位置 \(j\),若 \(j<i\),顯然刪掉 \(j\) 無任何影響;否則考慮 \(i<k<j\),\(s_k\) 必然取 X
或 Y
。那麼從 \(j-1\) 逆序刪除到 \(i+1\),最後刪除掉 \(j\),繼續迭代。容易(真的容易)看出這就是最大化權值的方案。
那麼Anna 需要告訴 Bruno 哪些資訊呢?——唯一的一個 \(i\),和若干 \(j\)。一個小小的壓縮方式是,對於連續的 Z
,僅保留最右端的。特別地,在標記 X
的 \(1\)
觀察標稱可知,取 \(W=63\),此時一段的總情況數接近 \(2^{44}\),損失較小。運算過程當然是 \(\mathcal O(n)\) 的,資訊長度也就比 \(7\times10^4\) 少一百來次。
\(\mathcal{Code}\)
Anna.cpp
/* Clearink */ #include "Anna.h" #include <vector> #ifndef MY_REP_DEFINED #define MY_REP_DEFINED #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 ) #endif namespace { typedef unsigned long long ULL; const int MAXN = 1e5, W = 63, B = 44; int n; std::vector<char> s; bool key[MAXN + W + 5]; ULL fib[W + 5]; inline void mark() { int i = 0; while ( i < n && s[i] != 'X' ) ++i; key[i] = true; for ( int j = i + 1; j < n; ++j ) { while ( j < n && s[j] != 'Z' ) ++j; while ( j + 1 < n && s[j + 1] == 'Z' ) ++j; if ( i >= n || j >= n ) break; key[j + 1] = true; } } inline void encode() { fib[0] = 1, fib[1] = 2; rep ( i, 2, W ) fib[i] = fib[i - 1] + fib[i - 2]; for ( int l = 0; l <= n; l += W ) { ULL msg = 0; rep ( i, l, l + W - 1 ) if ( key[i] ) { msg += fib[repi - i]; } rep ( i, 0, B - 1 ) Send( msg >> i & 1 ); } } } // namespace. void Anna( int n, std::vector<char> s ) { ::n = n, ::s = s; mark(), encode(); }
Bruno.cpp
/* Clearink */
#include "Bruno.h"
#include <vector>
#ifndef MY_REP_DEFINED
#define MY_REP_DEFINED
#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 )
#endif
namespace {
typedef long long ULL;
const int MAXN = 1e5, W = 63, B = 44;
ULL fib[W + 5];
int n;
std::vector<int> msg;
bool key[MAXN + W + 5];
inline void decode() {
fib[0] = 1, fib[1] = 2;
rep ( i, 2, W ) fib[i] = fib[i - 1] + fib[i - 2];
for ( int l = 0; l < msg.size(); l += B ) {
ULL val = 0;
per ( i, l + B - 1, l ) val = val << 1 | msg[i];
rep ( i, l / B * W, i + W - 1 ) {
if ( val >= fib[repi - i] ) {
key[i] = true, val -= fib[repi - i];
}
}
}
}
inline void solve() {
int i = 0;
while ( i < n && !key[i] ) Remove( i++ );
if ( i == n ) return ;
for ( int j = i + 1, las = i; j < n; ) {
while ( j < n && !key[j + 1] ) ++j;
per ( k, j - 1, las + 1 ) Remove( k );
if ( j < n ) Remove( las = j++ );
}
Remove( i );
}
} // namespace.
void Bruno( int n, int l, std::vector<int> msg ) {
::n = n, ::msg = msg;
decode(), solve();
}