2011-06-16 17:53:26Morris

a068. E. 看動畫 加强版

內容 :

小 米很喜歡看動畫,他會把看過的動畫都存到硬碟裡,這樣以後才可以再翻出來複習。但是因為他實在是有太多動畫了,一顆硬碟擺不下,所以他買了很多顆硬碟來 存。為了方便以後尋找,每一個硬碟都有一個編號,還有上面存了哪些動畫,動畫是以集為單位,一部動畫可能有很多集,但是一集一定會放在同一顆硬碟不會分在 兩顆。

有一天,當他想要把 OOXX 重看一遍時,發現一個麻煩的問題,動畫當然就是要從第一集開始一集集依序看完,但是不同集的動畫不一定放在同一個硬碟裡,因此要看完一部動畫可能會用到很 多顆硬碟。硬碟當然是要接上電腦才能用,但是電腦的 USB 接頭是有限的,因此可能沒有辦法一次把全部的硬碟接上去,所以當你看完一集時可能需要抽換硬碟才能看到下一集。當然如果現在連在電腦上的硬碟已經有你要看 的那一集那就可以不用換。因為一直換硬碟實在是太麻煩了,會影響看動畫的心情。所以他把他想看的動畫存在哪一顆硬碟中依序跟你講,希望請你寫一個程式來決 定怎麼抽換硬碟才能使抽換次數降到最低。

舉例來說,動畫可能依序放在 5 4 3 2 1 這五個硬碟中,電腦上有三個 USB 接頭,最少需要兩次抽換才能看完整部動畫。方法如下,首先先把 5 4 3 接上電腦,之後把 5 4 拔掉換成 2 1,這樣就可以全部看完。

輸入說明 :

第一行有一個整數代表總共有幾筆測試資料。
每一筆測試資料有兩行。
第一行有 N, M 兩個整數,N 代表動畫總共有幾集,M 代表有幾個 USB 接頭。
第二行有 N 個整數 A1 到 AN,代表依序要使用的硬碟編號。

 N ≤ 1000000, M ≤ 10000, 0 ≤ An ≤ 100000, 0 < T < 10

http://zerojudge.tw/ShowProblem?problemid=a068

輸出說明 :

每一筆測試資料輸出一個整數,代表最少要抽換多少次硬碟。

範例輸入 :

2
5 5
1 2 3 4 5
5 3
5 4 3 2 1

範例輸出 :

0
2

提示 :

NPSC d592: E. 看動畫 加强版

出處 :

NPSC 加强 (管理:liouzhou_101)



作法 : greedy
若槽上已滿,選擇插槽上下次使用最遠的拔除

作法必須很快,搜尋不能用O(N)
必須用O(1)的heap 找極值,修改O(logN)
因此普通的heap 行不通,也不是不行,記憶體會很大
因此寫個映射,來做修改
詳細 :
http://hi.baidu.com/prayan1988/blog/item/b7f68f39ba3288f8b311c74c.html
可以用來優化 最短路徑演算法,大致上就是這樣

/**********************************************************************************/
/*  Problem: a068 "E. 看動畫 加强版" from NPSC 加强                       */
/*  Language: C                                                                   */
/*  Result: AC (968ms, 9032KB) on ZeroJudge                                       */
/*  Author: morris1028 at 2011-06-16 09:45:20                                     */
/**********************************************************************************/


#include<stdio.h>
int next[1000001], pre[100001];
int A[1000001], L, set[100001];
char USB[100001];
struct  Heap {
    int x, node;
}Heap[10001];/*max heap*/
void Swap(int P, int S) {
    int T;
    T=Heap[P].x, Heap[P].x=Heap[S].x, Heap[S].x=T;
    T=Heap[P].node, Heap[P].node=Heap[S].node, Heap[S].node=T;
    set[Heap[S].node] = S, set[Heap[P].node] = P;
}
void siftup (int site) {
    int S = site, P = site >> 1;
    while(S >= 2 && Heap[P].x < Heap[S].x)
        Swap(P, S), S = P, P = S >> 1;
}
void siftdown(int site) {
    int P = site, S = site << 1;
    while(S <= L) {
        if(S < L && Heap[S+1].x > Heap[S].x)    S++;
        if(Heap[P].x >= Heap[S].x)    break;
        Swap(P, S), P = S, S = P << 1;
    }
}
void ins(int site, int value, int t) {/*insert new node*/
    Heap[site].node = value;
    Heap[site].x = next[t];
    set[value] = site, USB[value] = 1;
    siftup(site);
}
void del() {/*delete last node*/
    Swap(1, L), L--;
    siftdown(1);
}
int Input() {
    char cha;
    unsigned int x = 0;
    while(cha = getchar())
        if(cha != ' ' && cha != '\n') break;
    x = cha-48;
    while(cha = getchar()) {
        if(cha == ' ' || cha == '\n') break;
        x = x*10 + cha-48;
    }
    return x;
}
main() {
    int t, n, m;
    scanf("%d", &t);
    while(t--) {
        scanf("%d %d", &n, &m);
        int a, Ans = 0;
        for(a = 0, L = 0; a < 100001; a++) /*initiate*/
            pre[a] = 0, USB[a] = 0;
        
        for(a = 1; a <= n; a++) {
            A[a] = Input();
            if(pre[A[a]])
                next[pre[A[a]]] = a;
            pre[A[a]] = a;
        }

        for(a = 0; a < 100001; a++)
            if(pre[a])
                next[pre[a]] = n+1;       
        for(a = 1; a <= n; a++) {
            if(USB[A[a]]) {/*heap->p (next adjust)*/
                Heap[set[A[a]]].x = next[a];
                siftup(set[A[a]]);
                continue;
            }
            if(L == m) {/*pull out*/
                Ans++;
                USB[Heap[1].node] = 0;/*max pull out*/
                del();
            }
            L++, ins(L, A[a], a);
        }
        printf("%d\n", Ans);
    }
    return 0;
}