【九度】题目1540:麦霸

108 篇文章 0 订阅
102 篇文章 5 订阅
题目地址 http://ac.jobdu.com/problem.php?pid=1540
题目描述:
        GrassLand酷爱K歌,俗称麦霸,每次去KTV他都会为自己点许多歌曲。
        给定点唱机的操作序列,GrassLand希望知道他所点的每首歌曲将会在什么时间开始播放。
        点唱机的操作主要是对点唱机已选列表的操作,包括:
        1.top x,将已选列表中第x首歌曲,置于已选列表顶端。
        2.delete x,将已选列表中第x首歌曲从已选列表中删除。数据保证前两种操作中的x不大于当时已选列表中歌曲的数目,已选列表头部的歌曲记为第一首。
        3.add val flag,将一首长度为val(1<=val<=1000)的歌曲加入已选列表尾端,当flag为1时代表该首歌是GrassLand所点,为0时由他人所点。
        点唱机每一秒的操作逻辑如下:
        1.若当前没有歌曲正在播放,且已选列表不为空,则播放已选列表头部的歌曲,并将其从已选列表中删除;否则不进行任何操作。
        2.响应用户的操作,并对已选列表进行相应操作。
        3.若当前歌曲已经播放完毕,结束播放。注意,若一首长度为v的歌曲在时刻x时开始播放,则其播放时间为[x,x+v),也就是说,若没有其他操作发生,它会在时刻x+v-1时结束播放。
        除此之外,点唱机还提供了一种,针对正在播放歌曲的操作:
       1.cut,即设置当前正在播放的歌曲,在cut操作发生的时刻,播放完毕。若此时没有歌曲正在播放,则忽略该操作。
       初始时为0时刻,点唱机没有正在播放的歌曲,已选列表为空。
输入:
       输入包含多组测试用例,每组测试用例的开头为一个整数k(1<=k<=1000),代表共有k个点唱机操作。
       接下去k行,每行描述一个操作,其格式为”t+如上四种操作中的一种“,t(1<=t<=1000000)表示该操作发生的时刻,如
       3 top 2,表示在时刻3将已选列表中的第二首歌曲置顶。数据保证在一个时刻内仅一个操作,且输入数据按照t递增顺序给出。
输出:
        对于每组测试用例输出若干行,代表GrassLand所点的歌曲开始播放的时间刻度(所有被正在播放过的歌曲),播放时间按照升序排列。
样例输入:
         7
        1 add 15 1
        2 add 16 1
        3 add 10 0
        4 add 16 1
        5 top 2
        6 delete 3
        7 cut
样例输出:
        2
       18
        这个题目有点好玩,用不到什么复杂的算法和数据结构,却是训练编程基本功底的不错的题目。同时也推荐练习 Jobdu 题目1326:Waiting in Line
        虽说描述复杂,但是思路确实不难。
        给的操作有4种,add,delete,top和cut,一一分析。
        add,这个操作需要耗时1秒,如果当前歌曲列表为空的话,那么添加歌曲的播放时间为操作时间+1。如果上一首歌已播放完毕,那么添加歌曲的播放时间为操作时间+1,这里涉及到add操作所花的时间1秒。否则的话,添加歌曲的播放时间为上一首歌的结束时间。
        cut,切歌的话始终切的是当前歌曲,需要判断当前是否有歌曲播放,如果没有,就不做任何操作。获取当前歌曲是在list中的位置,将结束时间修改为当前时间。当前歌曲之后的所有歌曲的开始时间都需要修改。注意cut之后的下一首歌曲的播放时间为当前时间+1,因为操作需要一个时间点。
        del,因为删除的歌曲一定在列表中,所以只需要找到删除的歌曲在list中的序号。排在删除之后第一个的开始时间为删除序号前一个的结束时间,其他依次类推。
        top,top的时候考虑一下,如果已选列表(不包括正在播放的)只有一首,并且top的歌曲号也是1,就不做任何操作了。如果top的那个时刻刚好是当前歌曲结束的时间点,那么top之后的那首歌曲的播放时间应该是当前时间+1;
        剩下的操作就是对列表里的歌曲的开始时间和结束时间做操作的过程了,没什么难度吧。
        不过我的代码还是稍微有些复杂,如果后续有时间,就优化一下,顺便写写C++版本。这里只有Java版本。

Java AC

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.List;
 
public class Main {
    /*
     * 1540
     */
    private static int currentTime;
    private static List<Song> songList;
    public static void main(String[] args) throws IOException {
        StreamTokenizer st = new StreamTokenizer(new BufferedReader(
                new InputStreamReader(System.in)));
        while (st.nextToken() != StreamTokenizer.TT_EOF) {
            songList = new ArrayList<Song>();
            int n = (int)st.nval;
            while (n > 0) {
                n--;
                st.nextToken();
                currentTime = (int)st.nval;
                st.nextToken();
                String operate = st.sval;
                if (operate.equals("add")) {//将歌曲添加到列表尾
                    st.nextToken();
                    int len = (int)st.nval;
                    st.nextToken();
                    int isMine = (int)st.nval;
                    addSong(len, isMine);
                }else if (operate.equals("top")) {
                    st.nextToken();
                    int num = (int)st.nval;
                    topSong(num);
                }else if (operate.equals("delete")) {
                    st.nextToken();
                    int num = (int)st.nval;
                    delSong(num);
                }else {//cut
                    cutSong();
                }
            }
            int size = songList.size();
            for (int i = 0; i < size; i++) {
                Song song = songList.get(i);
                if (song.isMine == 1) {
                    System.out.println(song.startTime);
                }
            }
        }
    }
    private static void addSong(int len, int isMine) {
        int startTime = currentTime;
        //添加歌曲的时候需要判断一下,如果列表为空的话,那么添加歌曲的播放时间为操作时间+1
        if (songList.isEmpty()) {
            startTime = currentTime + 1;
        }else {
            int size = songList.size();
            Song lastSong = songList.get(size-1);
            int endTime = lastSong.endTime;
            //如果上一首歌已播放完毕,那么添加歌曲的播放时间为操作时间+1
            if (currentTime >= endTime) {
                startTime = currentTime + 1;
            }else {//否则的话,添加歌曲的播放时间为上一首歌的结束时间
                startTime = endTime;
            }
        }
        Song song = new Song(startTime, startTime + len, len ,isMine);
        songList.add(song);
    }
    private static void cutSong() {
        int size = songList.size();
        int currentTop = -1;
        List<Song> tempList = new ArrayList<Song>();
        for (int i = 0; i < size; i++) {
            Song song = songList.get(i);
            int endTime = song.endTime;
            if (currentTime >= song.startTime && currentTime < endTime) {
                currentTop = i;
                break;
            }
            tempList.add(song);
        }
        //切歌的话始终切的是当前歌曲,需要判断当前是否有歌曲播放,如果没有,就不做任何操作。
        if (currentTop == -1) {
            return;
        }
        //获取当前歌曲是在list中的位置,将结束时间修改为当前时间。
        //当前歌曲之后的所有歌曲的开始时间都需要修改。
        //注意cut之后的下一首歌曲的播放时间为当前时间+1,因为操作需要一个时间点。
        Song cutSong = songList.get(currentTop);
        tempList.add(new Song(cutSong.startTime, currentTime, cutSong.len, cutSong.isMine));
        for (int i = currentTop+1; i < size; i++) {
            Song song = songList.get(i);
            int newSize = tempList.size();
            Song newSong = tempList.get(newSize - 1);
            int endTime = newSong.endTime;
            if (i == currentTop + 1) {
                endTime = currentTime + 1;
            }
            tempList.add(new Song(endTime, endTime + song.len,song.len, song.isMine));
        }
        songList.clear();
        songList.addAll(tempList);
        tempList.clear();
         
    }
    private static void delSong(int num) {
        int size = songList.size();
        int needDel = 0;
        int rankNum = 0;
        List<Song> tempList = new ArrayList<Song>();
        for (int i = 0; i < size; i++) {
            Song song = songList.get(i);
            int endTime = song.endTime;
            if (currentTime >= endTime ) {
                tempList.add(song);
                continue;
            }
            if (currentTime >= song.startTime && currentTime < endTime) {
                tempList.add(song);
                continue;
            }
            rankNum++;
            if (rankNum == num) {
                needDel = i;
                break;
            }
            tempList.add(song);
        }
        //因为删除的歌曲一定在列表中,所以只需要找到删除的歌曲在list中的序号。
        //排在删除之后第一个的开始时间为删除序号前一个的结束时间,其他依次类推。
        for (int i = needDel+1; i < size; i++) {
            Song delSong = songList.get(i);
            int newSize = tempList.size();
            Song newSong = tempList.get(newSize - 1);
            tempList.add(new Song(newSong.endTime, newSong.endTime + delSong.len,delSong.len, delSong.isMine));
        }
        songList.clear();
        songList.addAll(tempList);
        tempList.clear();
         
    }
    private static void topSong(int num) {
        int size = songList.size();
        int rankNum = 0;
        int currentTop = 0;
        int needMove = size - 1;
        List<Song> tempList = new ArrayList<Song>(); 
        for (int i = 0; i < size; i++) {
            Song song = songList.get(i);
            int endTime = song.endTime;
            if (currentTime >= endTime ) {
                tempList.add(song);
                continue;
            }
            if (currentTime >= song.startTime && currentTime < endTime) {
                currentTop = i;
                tempList.add(song);
                continue;
            }
            rankNum++;
            if (rankNum == num) {
                needMove = i;
                break;
            }
        }
        //top的时候考虑一下,如果已选列表(不包括正在播放的)只有一首,并且top的歌曲号也是1,就不做任何操作了。
        if (num == 1 && needMove == size - 1) {
            return;
        }
        //如果top的那个时刻刚好是当前歌曲结束的时间点,那么top之后的那首歌曲的播放时间应该是当前时间+1;
        Song currentSong = songList.get(currentTop);
        int topEndTime = currentSong.endTime;
        if (topEndTime == currentTime) {
            topEndTime += 1;
        }
        Song needSong = songList.get(needMove);
        Song newSong = new Song(topEndTime,topEndTime+needSong.len, needSong.len, needSong.isMine);
        tempList.add(newSong);
        for (int i = currentTop+1; i < size; i++) {
            Song song = songList.get(i);
            if (i == needMove) {
                continue;
            }
            int newSize = tempList.size();
            Song lastSong = tempList.get(newSize - 1);
            tempList.add(new Song(lastSong.endTime, lastSong.endTime + song.len,song.len, song.isMine));
        }
        songList.clear();
        songList.addAll(tempList);
        tempList.clear();
    }
     
    private static class Song{
        private int startTime;
        private int endTime;
        private int len;
        private int isMine;
        public Song(int startTime, int endTime, int len, int isMine) {
            super();
            this.startTime = startTime;
            this.endTime = endTime;
            this.len = len;
            this.isMine = isMine;
        }
    }
}
/**************************************************************
    Problem: 1540
    User: wzqwsrf
    Language: Java
    Result: Accepted
    Time:1980 ms
    Memory:48224 kb
****************************************************************/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值