旋律压缩

GitHub跳转原题关系图返回列表

无限循环播放只是周期重复,先用 c mod L 折回单周期,再把压缩串解析成段并用前缀和定位对应音符。

OJ: roj

题目 ID: 20018

难度:普及-

标签:字符串前缀和模拟

创建: 2026-08-28 22:10

更新: 2026-10-07 13:50

题目描述

连续相同音符压缩为「字母+次数」段,如 a4b1c2d4。给定压缩串 s′s' 和整数 cc,求解压后旋律无限循环播放时第 cc 个(从 0 开始)音符。

输入一行 s′s'、一行 cc,输出对应小写字母。样例:r2d2 + 8 → r;a4b1c2d10 + 100 → d。数据范围 ∣s′∣≤2×105|s'|\le 2\times10^5,c≤1012c\le10^{12}。

思路

把压缩串解析成音符段并累计单周期长度 LL;令 k=c mod Lk=c\bmod L,再用前缀和扫描定位 kk 所在段。

参考代码

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-08-28 21:26
 * update_at: 2026-08-28 21:26
 */
#include <bits/stdc++.h>
using namespace std;

const int MAXN = 200005;

string s;           // 压缩旋律串,只含小写字母和数字
long long c;        // 询问的第 c 个音符,从 0 开始编号
int m;              // 段的个数
char chs[MAXN];     // chs[i]:第 i 段的音符
long long cnts[MAXN]; // cnts[i]:第 i 段音符连续出现的次数
long long sum;      // 单周期总长度 L

// 把压缩串解析成 (音符, 次数) 段,并累加单周期长度。
void parse() {
    int n = (int)s.length();
    int i = 0;
    while (i < n) {
        chs[++m] = s[i]; // 当前位置一定是字母(音符)
        i++;
        long long cnt = 0;
        // 次数可能占多位数字,如 d10 表示 10 个 d,逐位拼出来。
        while (i < n && s[i] >= '0' && s[i] <= '9') {
            cnt = cnt * 10 + (s[i] - '0');
            i++;
        }
        cnts[m] = cnt;
        sum += cnt;
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> s >> c;

    parse();

    // 无限循环:第 c 个音符只取决于它在单周期内的位置 k = c mod L。
    c %= sum;

    // 前缀和定位:第 i 段覆盖区间 [pre, pre + cnts[i]),
    // 第一个 pre + cnts[i] > c 的段就是答案段。
    long long pre = 0;
    for (int i = 1; i <= m; i++) {
        if (pre + cnts[i] > c) {
            cout << chs[i] << '\n';
            return 0;
        }
        pre += cnts[i];
    }

    return 0;
}