Live2D

Solution -「JOISC 2021」古老的机器

Description

  Link.

  这是一道通信题。

  对于长度为一个 n,仅包含字符 X, Y, Z 的字符串 s,将其中 n 个字符按任意顺序删去,定义删除方案的权值为在子串 XYZ 中删除 Y 的次数。实现两个函数:

  • void Anna(int N, std::vector<char> S),获取字符串信息,传递不超过 7×10401 位用于通信;
  • void Bruno(int N, int L, std::vector<int> A),获取通信信息,给出权值最大的删除方案。

  n105

Solution

  先看看怎么求最大权值。考虑当前最左侧 X 的位置 i 与最左侧 Z 的位置 j,若 j<i,显然删掉 j 无任何影响;否则考虑 i<k<jsk 必然取 XY。那么从 j1 逆序删除到 i+1,最后删除掉 j,继续迭代。容易(真的容易)看出这就是最大化权值的方案。

  那么 Anna 需要告诉 Bruno 哪些信息呢?——唯一的一个 i,和若干 j。一个小小的压缩方式是,对于连续的 Z,仅保留最右端的。特别地,在标记 X1 的后面强制补一个 0 站位,我们就把信息串转化为长度为 n+1,不存在连续 1 的数字串。每 W 为一段,利用 Fibonacci 数列求出每段的字典序编号,再转化为二进制输出,就能传递信息啦。

  观察标称可知,W=63,此时一段的总情况数接近 244,损失较小。运算过程当然是 O(n) 的,信息长度也就比 7×104 少一百来次。

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();
}

posted @   Rainybunny  阅读(220)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示