#P2777. 第1题-字符串和声
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 132
            Accepted: 19
            Difficulty: 2
            
          
          
          
                       所属公司 : 
                              阿里
                                
            
                        
              时间 :2025年3月30日-阿里云(开发岗)
                              
                      
          
 
- 
                        算法标签>模拟          
 
第1题-字符串和声
解题思路
本题的关键是对输入的字符串进行拆分、处理,并根据给定的延迟p计算和声字符串。具体步骤如下:
1. 题目解析
- 原始字符串由若干个小节(由
|分隔)组成。 - 对于每一个小节,和声字符串在小节前加上p个下划线(
_)来延迟输出。 - 如果p大于或等于该小节的长度,则和声字符串由全下划线组成。
 - 如果p小于小节的长度,则和声的前p个字符是下划线,剩余的部分是原小节的内容。
 
2. 处理步骤
- 读取输入,先获取字符串的总长度n和延迟长度p。
 - 按
|分割字符串,得到每个小节。 - 对每个小节进行处理:
- 如果延迟p大于或等于小节长度,则和声部分全部是下划线。
 - 否则,和声字符串前面填充p个下划线,后面保留原小节内容的剩余部分。
 
 - 最后,将每个小节的和声字符串用
|连接起来输出。 
3. 复杂度分析
- 时间复杂度:每次处理一个小节,我们只需要扫描每个小节一次,因此时间复杂度为O(n),其中n是原字符串的总长度。
 - 空间复杂度:需要存储原字符串以及和声字符串,因此空间复杂度为O(n)。
 
Python代码实现
# 读取输入
n, p = map(int, input().strip().split())  # n是总长度,p是延迟长度
# 处理每行输入
while 1:
    try:
        s = input().strip()  # 每一行的输入
        if s:  # 如果有输入
            # 去掉两侧的竖线后,按竖线分割小节
            sections = s.split('|')[1:-1]
            result = []
            # 对每个小节处理
            for section in sections:
                if p >= len(section):
                    # 如果延迟p大于等于当前小节的长度,和声全部是下划线
                    result.append('_' * len(section))
                else:
                    # 否则,和声由p个下划线和剩余部分组成
                    result.append('_' * p + section[:len(section) - p])
            # 输出和声
            print('|' + '|'.join(result) + '|')
    except EOFError:  # 如果输入结束
        break
Java代码实现
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();  // 总字符串长度
        long p = sc.nextLong(); // 延迟长度
        sc.nextLine();  // 吸收换行符
        while (sc.hasNextLine()) {
            String s = sc.nextLine().trim();  // 去掉首尾空格
            if (s.isEmpty()) continue;
            StringBuilder sb = new StringBuilder("|");
            String mid = s.substring(1, s.length() - 1);  // 去掉首尾竖线
            String[] parts = mid.split("\\|");
            for (int i = 0; i < parts.length; i++) {
                sb.append(deal(parts[i], p));  // 处理每个小节
                if (i < parts.length - 1) sb.append("|");  // 连接小节
            }
            sb.append("|");
            System.out.println(sb.toString());  // 输出结果
        }
        sc.close();  // 关闭Scanner
    }
    private static String deal(String s, long p) {
        return (s.length() <= p) ? "_".repeat(s.length()) : "_".repeat((int) p) + s.substring(0, s.length() - (int) p);
    }
}
C++代码实现
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
    int n, p;
    cin >> n >> p;
    cin.ignore();  // 忽略换行符
    string s;
    while (getline(cin, s)) {
        if (s.empty()) continue;
        // 分割小节
        vector<string> sections;
        size_t start = 1, end;
        while ((end = s.find('|', start)) != string::npos) {
            sections.push_back(s.substr(start, end - start));
            start = end + 1;
        }
        // 处理每个小节
        string result = "|";
        for (const string §ion : sections) {
            if (p >= section.length()) {
                result += string(section.length(), '_');
            } else {
                result += string(p, '_') + section.substr(0, section.length() - p);
            }
            result += "|";
        }
        // 输出和声
        cout << result << endl;
    }
    return 0;
}
        题目内容
小歪正在学习字符串和声,字符串仅由小写字母和连接线′−′构成。我们使用竖线′∣′来划分小结,例如, ∣do−do−re∣re−−−∣ 代表两个小结,其中,第一个小结长度为8,即"do−do−re";第二个小结长度为5,即"re−−−"
随后,我们定义字符串的和声为:字符串和声小节数量和各个小结的长度均与原字符串一致,唯一的区别是其会比原字符串晚p个长度出现,和声未出现时使用下划线替代空白位置,小结结束时未输出完整的和声会被直接截断;更具体地,先在每一个小节前面加上p条下划线,随后截取原来的小节的长度位,得到每一个小节的和声。例如,当p=2时,第一小节变为"_ _ _do−re−re",再截取前8位,得到第一小节的和声 " _ _do−do−",上方样例的和声最终可以唯一地表示为| _ do−do−| _ _re−|
现在,对于给出的字符串和整数p,请你直接输出和声!
输入描述
第一行输入两个整数n,p(1≦n≦3×105;0≦p≦109)代表原字符串总长度(包括∣在内)和和声延迟的长度。 此后若干行,一共输入n个字符,代表原字符串。保证每行的首末均为竖线(∣),每个小结的长度至少为1,小结中的字符仅为小写字母和连接线(−)。
输出描述
根据输入,输出若干行,代表和声字符串。
样例1
输入
16 2
|do-do-re|re--|
输出
|_do-do-|_re-|
说明
这个样例已经在题面中加以解释。
样例2
输入
15 0
|ciallo|
|-|
|--|
输出
|ciallo|
|-|
样例3
输入
7 2
|-|
|--|
输出
|_|
|__|
样例4
输入
16 2
|do-do-re|mi---|
输出
|__do-do-|__mi-|
说明
第一节和声:do−do−re 变为_ _ do−do− 第二节和声:mi−−−变为 _ _mi−