题解 P2614 【计算器弹琴】

· · 题解

题目链接

题意概述

输入一段乐谱,共 n 行,速度为每分钟 t,有不同的音符,用不同的符号表示,要求出弹玩这段乐谱要用多少,答案保留整数部分。

题目分析

首先,这是一道明显的模拟,只要认真仔细一般就能做对。

普及一下音乐知识:

  1. - 延时线延长一拍
  2. _ 减时线,题目中用 () 表示,一条减时线 0.5 拍,两条 0.25 拍,同理可以推出 n 条减时线为 \frac 1 {2^{n}}
  3. . 附点,延长前一个音的的一半,注意是前一个音的一半。

好了,其实题目中有很多迷惑你的东西,比如说音符高低,此题要计算的是节拍数,与音符高低无关

我们分情况解决,记录下减时线和延时线的数量,遇到延时线就延长,遇到减时线就减短,遇到附点,就延长上一个的一半。

注意:有一种特殊情况 1-. ,这种情况为 3 拍,要特殊判断。

详细解释请看代码:

代码

#include <bits/stdc++.h> // 万能头
using namespace std;
int n, t; // n 为字符串个数,t 为速度(表示一分钟多少拍)。
double cnt[10100]; // 表示到当前字符为止所需要的时间。
int num; // 记录左括号的个数。
int sum; // 记录延时线的个数。
string s; // string 类型可以直接加减。
int main() {
    scanf("%d %d\n", &n, &t); // 注意要加一个换行符,不然它会认为你输的换行也是一个字符串。 
    for (int i = 1; i <= n; i++) {
        string ss; // 当前字符串。
        getline(cin, ss); // getline 输入一行。
        s += ss; // 这样可以累加字符串。
    } 
    // 输入,并将所有字符串累加起来。
/* ------------------------------------- */
    for (int i = 0; i < s.size(); i++) { // size 获取字符串长度,也可用 length。
        switch (s[i]) { // 判断当前字符为那种字符。
            case '-': sum++, cnt[i] = cnt[i - 1] + 1; break; // 如果是延时线,那么就加一拍,千万不要忘了 break,我就差点忘了。
            // 注意:附点有特殊情况,比如说:1-. 为 2 拍加 1 拍等于 3 拍。  
            case '.': {
                if (s[i - 1] == '-') {
                    cnt[i] = (sum + 1) * 0.5 + cnt[i - 1]; // sum + 1 就是上一音符的时长。
                    // 相当于把到上一个音符为止的节拍数加上上一拍的一半,if 后面的那一句也一样。 
                    sum = 0; // 将 sum 清零。
                    break;
                }
                cnt[i] = 1 / pow(2, num) * 0.5 + cnt[i - 1];
                // num 为减时线的个数。
                /*
                    如果 num = 1,那么它就是 1/2 拍,也就是 1/(2^1)。
                    如果 num = 2,它就是 1/4 拍,也就是 1/(2^2)。
                    其他同理。
                */
                break;
            } // 如果是附点,就加上上一音符的一半。
            case '(': sum = 0, num++, cnt[i] = cnt[i - 1]; break; // 如果是减时线,就记录一下是几条减时线。
            case ')': sum = 0, num--, cnt[i] = cnt[i - 1]; break; // 如果是右括号,就减回去。 
            case ' ': cnt[i] = cnt[i - 1]; break;
            case '\n': cnt[i] = cnt[i - 1]; break;
            case '\r': cnt[i] = cnt[i - 1]; break; // 如果是空格或回车就直接赋为上一个值。 
            default: sum = 0, cnt[i] = 1 / pow(2, num) + cnt[i - 1]; break;
            // 不用管是哪个音,这和节拍没有关系,所以都算成其他情况。 
        } 
    }
    // 核心部分
/* --------------------------------------- */
    printf("%d\n", (int)(cnt[s.size() - 1] * 60 / t)); // 由于我们的 t 是一分钟的拍子数,所以最后要乘以 60,不要忘了取整。
    // 输出
    return 0; // return 是个好习惯!
} // ~完美结束~

AC 记录 (别忘了开 O2)

题目推荐

https://www.luogu.com.cn/problem/P2108

本蒟蒻第二次写题解,希望对大家有帮助!

最后再说一句,大家不要抄袭哦!