2026CCPC长春站I题新思路
前言
2026 CCPC 长春站 I 题新思路
题面
https://qoj.ac/contest/4582/problem/22918
通信题,多测
给定测试次数 \(T\) 与通信标志 \(\text{op}\)
若 \(\text{op} = 1\):
给定一个长度为 \(n\) 的01字符串 \(P\)。
你需要输出一个长度为至多 \(\left\lfloor\frac{3n}{2}\right\rfloor\) 的01字符串 \(Q\),满足其无子串 000 与 111。
若 \(\text{op} = 2\):
给定你在 \(\text{op} = 1\) 时输出的字符串 \(Q\),你需要还原 \(P\)。
题解
用连续段表示字符:用长度为 \(1\) 表示出现多的字符,长度为 \(2\) 表示出现少的字符,并钦定第一个字符为真正的第一个字符。
思路
先不考虑 \(n\) 为奇数的边界情况。
那么我们显然要用长度为 \(3\) 的串表示长度为 \(2\) 的串。
长度为 \(3\) 的合法串有 \(6\) 个:
001,110,011,100,010与101。
其中第 1/2 个串,若左侧为 \(0/1\) 则会不合法,第 3/4 个串,若右侧为 \(1/0\) 则会不合法。
一个自然的想法是:
将第 1/2 个串、第 3/4 个串,组成一组,分别看左、右侧串决定选谁。
若二者相遇,则钦定前者选 001 后者选 011。于是选谁就可以前后扫一遍线性解决。
考虑 \(n\) 为奇数时,末尾剩 \(1\) 个直接输出即可。
实现
https://qoj.ac/submission/3240577
#include <iostream>
#include <map>
#include <vector>
using namespace std;
int tt;
int n, op;
string P, Q;
vector<int>Pi, Qi;
map<string, int> Ptoi, Qtoi;
map<int, string> itoP, itoQ;
void init() {
Ptoi["00"] = 1; itoP[1] = "001"; itoP[-1] = "110";
Ptoi["01"] = 2; itoP[2] = "011"; itoP[-2] = "100";
Ptoi["10"] = 3; itoP[3] = "010";
Ptoi["11"] = 4; itoP[4] = "101";
Ptoi["0" ] = 5; itoP[5] = "0";
Ptoi["1" ] = 6; itoP[6] = "1";
Qtoi["001"] = Qtoi["110"] = 1; itoQ[1] = "00";
Qtoi["011"] = Qtoi["100"] = 2; itoQ[2] = "01";
Qtoi["010"] = 3; itoQ[3] = "10";
Qtoi["101"] = 4; itoQ[4] = "11";
Qtoi[ "0" ] = 5; itoQ[5] = "0";
Qtoi[ "1" ] = 6; itoQ[6] = "1";
}
void solve1(){
cin >> n >> P;
P = "#" + P;
Pi.clear();
for(int i = 1; i <= n-1; i += 2) {
Pi.push_back(Ptoi[P.substr(i, 2)]);
}
Pi.push_back(Ptoi[P.substr(2*(n/2)+1)]);
Q = "";
int lst = 1;
for(int i = 0; i < Pi.size(); i ++) {
switch (Pi[i]) {
case 1:
if(lst == 0) {
Pi[i] = - Pi[i];
break;
}
case 2:
case 4:
case 6:
lst = 1;
break;
default:
lst = 0;
break;
}
}
lst = 0;
for(int i = Pi.size()-1; i >= 0; i --) {
switch (Pi[i]){
case 2:
if(lst == 1) {
Pi[i] = - Pi[i];
break;
}
lst = 0;
break;
case 4:
case 6:
lst = 1;
break;
default:
lst = 0;
break;
}
}
for(auto p: Pi) {
Q += itoP[p];
}
cout << Q.size() << "\n" << Q << endl;
}
void solve2() {
cin >> n >> Q;
Q = "#" + Q;
Qi.clear();
for(int i = 1; i <= n-1; i += 3) {
Qi.push_back(Qtoi[Q.substr(i, 3)]);
}
Qi.push_back(Qtoi[Q.substr(3*(n/3)+1)]);
P = "";
for(auto q: Qi) {
P += itoQ[q];
}
cout << P.size() << "\n";
cout << P << endl;
}
int main() {
init();
cin >> tt >> op;
if(op == 1) while(tt --) solve1();
if(op == 2) while(tt --) solve2();
return 0;
}

浙公网安备 33010602011771号