[COCI2010-2011#7] GITARA
题目传送门
链接: 洛谷P6704
题目背景
Darko 有一个想象的外星朋友,他有十亿根手指。外星人快速拿起吉他,在网上找到一段简单的旋律并开始弹奏。
这个吉他像寻常一样有六根弦,令其用 1 1 1 到 6 6 6 表示。每根弦被分成 P P P 段,令其用 1 1 1 到 P P P 表示。
旋律是一串的音调,每一个音调都是由按下特定的一根弦上的一段而产生的(如按第 4 4 4 弦第 8 8 8 段)。如果在一根弦上同时按在几段上,产生的音调是段数最大的那一段所能产生的音调。
例:对于第 3 3 3 根弦,第 5 5 5 段已经被按,若你要弹出第 7 7 7 段对应音调,只需把按住第 7 7 7 段,而不需放开第 5 5 5 段,因为只有最后的一段才会影响该弦产生的音调(在这个例子中是第 7 7 7 段)。类似,如果现在你要弹出第 2 2 2 段对应音调,你必须把第 5 5 5 段和第 7 7 7 段都释放。
请你编写一个程序,计算外星人在弹出给定的旋律情况下,手指运动的最小次数。
题目描述
你有一个 6 × P 6 \times P 6×P 的矩阵 A A A,初始状态皆为 0 0 0。
对于所有要求 ( i , j ) (i,j) (i,j)
你需要满足要求:
-
此时 A i , j A_{i,j} Ai,j 状态为 1 1 1。
-
对于 A i , j + k ( k > 0 ) A_{i,j+k} (k>0) Ai,j+k(k>0) 状态为 0 0 0。
你在满足要求的情况下需要求状态转换最小次数。
输入格式
第一行包含两个正整数 n n n , P P P。它们分别指旋律中音调的数量及每根弦的段数。
下面的 n n n 行每行两个正整数 i i i , j j j,分别表示能弹出对应音调的位置——弦号和段号,其为外星人弹奏的顺序。
输出格式
一个非负整数表示外星人手指运动次数最小值。
样例 #1
样例输入 #1
5 15
2 8
2 10
2 12
2 10
2 5
样例输出 #1
7
样例 #2
样例输入 #2
7 15
1 5
2 3
2 5
2 7
2 4
1 5
1 3
样例输出 #2
9
提示
样例 1 解释
所有的音调都是由第二根弦产生的。首先按顺序按 8 8 8 10 10 10 12 12 12 ( c o u n t = 3 count=3 count=3)。然后释放第 12 12 12 段( c o u n t = 4 count=4 count=4)。最后,按下第 5 5 5 段,释放第 8 8 8 10 10 10 段 ( c o u n t = 7 count=7 count=7)。
样例 2 解释
对于每个操作,分别需要 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 0 0 0 2 2 2 次手指运动。
数据规模及约定
按下或释放一段弦各计一次手指运动。弹弦不算手指的移动,而是一个弹吉他的动作。(指你不需要管他怎么弹的,只需要按就是啦,说不定他可以用超能力呀)
对于 100 % 100\% 100% 的数据 n ≤ 5 × 1 0 5 n \le 5 \times 10^5 n≤5×105 , 2 ≤ P ≤ 3 × 1 0 5 2 \le P \le 3 \times 10^5 2≤P≤3×105
说明
本题满分 70 70 70 分。
译自 COCI2010-2011 CONTEST #7 T3 GITARA
解题思路
这题可以利用栈的思想
将每一种弦都用一种栈(本人太蒟,不会用STL)
如果有数进来时
就和栈顶比较大小
如果栈顶>进来的数
就要出栈
注意:
当 弹 1 5 1 6 1 5 时,虽然已经按过 1 5,但是也要先松开 1 6 的键,然后可以不用按 1 5 (用其他方法的小朋友们!敲黑板!做笔记!)
代码
#include <iostream>
using namespace std;
int a[7][300010];
int top[7];
int main(){
int n,p;
cin>>n>>p;
int ret=0;
for(int i=1;i<=n;i++){
int x,y;
cin>>x>>y;
while(y<a[x][top[x]]){
top[x]--;
ret++;
}
if(y>a[x][top[x]]){
a[x][++top[x]]=y;
ret++;
}
}
cout<<ret;
return 0;
}