对于这种损失信息的通信题,关键是在于找不变量那找不到怎么办 /ll
令 \(\{t_i\}=\texttt{1010}\cdots\),将 \(\texttt{01}\) 分别看做 \(-1\) 和 \(+1\),则归并后对 \(\{s_i\}\) 的前缀和影响不大。
此时问题转化为选择 \(10^{18}\) 个长度 \(\le 140\) 的 \(\texttt{01}\) 串 \(\{s_i\}\) 使得可以由 \(\text{merge}(s,t)\) 还原出 \(\{s_i\}\)。
具体来说,\(\{t_i\}\) 的影响是时不时会 \(\pm 1\),但前缀和 \(\in\{0,1\}\),所以构造如下:每个极长相同连续段长度都是 \(\ge 3\) 的奇数,除了第一段如果是连续 \(\texttt{1}\) 那么长度为偶数;对应的解码方法是前缀和到 \(+2\) 时记一个 \(\texttt 1\) 并归零,到 \(-2\) 时记一个 \(\texttt 0\) 并归零,然后把每个连续段长度 \(x\) 扩大到 \(2x+1\)(同样特判第一段)
这时候所需长度已经比较接近了,需要再优化细节卡卡常:
- 末尾加一堆交替的 \(\texttt{0}\) 和 \(\texttt{1}\);
- 开头加一个 \(\texttt{1}\),然后反转所有 \(\texttt{01}\)。
#include"Anna.h"
#include<bits/stdc++.h>
typedef long long LL;
typedef std::vector<int> VI;
namespace {
const int N = 150;
LL f[N];
}
int Declare(){
f[1] = f[2] = 1;
for(int i = 3;i < N;++ i)
f[i] = f[i-2] + f[i-3] + 1;
return 140;
}
std::pair<VI, VI> Anna(LL k){
-- k; int flg = k & 1; k >>= 1;
int len = 1; while(k >= f[len]) k -= f[len++];
VI s, t(len); s.reserve(len);
int fl = flg; s.push_back(fl);
for(int i = len;k;){
if(k <= f[i-2]){-- k; i -= 2;}
else {s.push_back(fl ^= 1); k -= f[i-2] + 1; i -= 3;}
s.push_back(fl); s.push_back(fl);
}
while(s.size() < len) s.push_back(fl ^= 1);
for(int i = 0;i < len;++ i) t[i] = flg ^ (i & 1);
return std::make_pair(s, t);
}
#include"Bruno.h"
#include<bits/stdc++.h>
typedef long long LL;
typedef std::vector<int> VI;
namespace {
const int N = 150;
LL f[N];
}
LL Bruno(VI u){
if(!f[1]){
f[1] = f[2] = 1;
for(int i = 3;i < N;++ i)
f[i] = f[i-2] + f[i-3] + 1;
}
LL ans = 0; int len = u.size() >> 1;
for(int i = 1;i < len;++ i) ans += f[i];
int flg = u[0], fl = flg, sum = 0;
for(int i = 1, j = len;i < u.size();++ i){
sum += 2 * u[i] - 1;
if(abs(sum) == 2){
if((sum == 2) == fl){++ ans; j -= 2;}
else {ans += f[j-2] + 1; j -= 3;}
fl = sum == 2; sum = 0;
}
}
return ans * 2 + flg + 1;
}