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;
}
posted @ 2026-10-22 00:25  Xie2Yue  阅读(35)  评论(0)    收藏  举报