题解 P2614 【计算器弹琴】
见贤思齐_Seakies · · 题解
题目链接
题意概述
输入一段乐谱,共
题目分析
首先,这是一道明显的模拟,只要认真仔细一般就能做对。
普及一下音乐知识:
-延时线,延长一拍。_减时线,题目中用()表示,一条减时线0.5 拍,两条0.25 拍,同理可以推出n 条减时线为\frac 1 {2^{n}} 拍。.附点,延长前一个音的的一半,注意是前一个音的一半。
好了,其实题目中有很多迷惑你的东西,比如说音符高低,此题要计算的是节拍数,与音符高低无关。
我们分情况解决,记录下减时线和延时线的数量,遇到延时线就延长,遇到减时线就减短,遇到附点,就延长上一个的一半。
注意:有一种特殊情况 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 是个好习惯!
} // ~完美结束~
(别忘了开 O2)
题目推荐
https://www.luogu.com.cn/problem/P2108
本蒟蒻第二次写题解,希望对大家有帮助!
最后再说一句,大家不要抄袭哦!