1. 程式人生 > >NOIP提高組--選擇客棧

NOIP提高組--選擇客棧

如果 urn 思考 代碼 之前 ret space 所有 ()

我看到有人用線段樹來寫而且想法和我的差不多,但是代碼有一點復雜,所以我就貼一下我的做法。


思路

首先一定知道純暴力50分差不多了,所以看到k非常的小,那麽就從k入手。

不知道有沒有人和我一樣是先枚舉顏色的,那麽我們來思考一下,對於每個相同顏色的客站之間[l,r],如果當前區間不能找到一個合理的咖啡廳,那麽一定會影響到和他連在一起的下一個不能找到咖啡廳的區間。那麽我們就將這個標記放在r這個節點上,那麽第一個節點我們就當做是0。

說的形象一點,就是看這個節點能和前面多少個相同顏色的客棧組成合法的方案。

如果當前的區間是合法的,那麽前面的所有點都是可以和這個點組成方案。


算法實現

每一次算出這個客棧之前有多少個相同顏色的客棧,然後我們通過一個標記,表示在與這個區間相連接的前面幾個區間內有多少個不合法的區間,每一次算的時候我們就需要把這些點數減掉。

如果當前的區間是不合法的,那麽我們就需要將這個標記+1,否則就將這個標記設置成0。


代碼

# include <bits/stdc++.h>
# define N 200005
# define Inf 0x3f3f3f3f
using namespace std ;
struct node {
    int c , v ; 
}a[N] ;
int n , k , p , ans = 0 ;
int main () {
    scanf( "%d%d%d" , &n , &k , &p ) ; 
    for ( int i = 1 ; i <= n ; i ++ ) scanf( "%d%d" , &a[i].c , &a[i].v ) ; 
    for ( int i = 0 ; i < k ; i ++ ) {
        int cnt = 0 , sub = Inf , tmp = 0 , re = 0 ; //re表示有多少連接的前區間不合法
        for ( int j = 1 ; j <= n ; j ++ ) {
            sub = min ( a[j].v , sub ) ;
            if ( a[j].c == i ) {
                tmp += cnt ++ ; 
                if ( sub > p ) tmp = max ( tmp - ++ re , 0 ) ;  
                else re = 0 ; 
                sub = a[j].v ; 
            } 
        }
        ans += tmp ;
    }
    printf( "%d\n" , ans ) ; 
    return 0 ;
}

NOIP提高組--選擇客棧