UOJ728 【JOISC2022】坏掉的设备 2 【通信,构造】

题目链接

对于这种损失信息的通信题,关键是在于找不变量那找不到怎么办 /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;
}
posted @ 2022-05-18 10:09  mizu164  阅读(203)  评论(0编辑  收藏  举报