【noip 2011】選擇客棧

去題面的傳送門

QAQ很巧妙的方法 O(n)就可以做
邊讀入邊處理
記錄:
①now:爲離當前客棧最近的,花費不超過p的客棧的座標
②sum[x]:已經對答案有過貢獻的(與它之後的客棧之間有最小花費不超過p的)顏色爲x的客棧的數量
③tot[x]:之前出現過的顏色爲x的客棧的數量
④h[x]:之前最後一次出現的顏色爲x的客棧(與當前客棧顏色相同且距離當前客棧最近的客棧)的座標

如何記錄答案?

因爲我們要找的是顏色相同的兩個客棧之間的最小花費小於p,所以只要在兩個客棧之間存在一個小於p的,那麼他們就是一種方案。所以我們記錄了now。如果now在上一個與它顏色相同的客棧之間,那麼就對答案有貢獻,這時答案應該加上前面所有與它相同顏色的客棧的數量,即tot[x],這時,sum[x]應更新爲tot[x]。反之,由於我們記錄的sum[x]沒有被更新,還是之前的,這時的ans+=sum[x]表示的是該客棧與所有在now之前的與它顏色相同的客棧組成的方案,這時,sum[x]不用更新,因爲上一個客棧並沒有與當前的客棧形成一種方案。tot[x]每次都要++,同時不要忘了更新h[x]。
注意:由於題目中說兩個客棧之間的客棧包括他們兩個本身,所以程序中第16、17行不要忘記加等號

由於sum和tot數組及答案的更新並不好理解,所以畫個圖解釋一下:
這裏寫圖片描述
如圖 客棧1,2,3,4,5號
上方的數字表示花費,p=3
我們主要說一下4號和5號答案的更新
(用1表示黑色,0表示紅色)
4號:
目前,tot[1]=2,sum[1]=0,h[1]=2,now=3
由於在4號和2號之間有花費小於p的客棧(即h[1]<=now),這時我們把sum[1]賦值爲tot[1],也就是之前出現過的顏色爲黑色的客棧都能與當前客棧形成方案,ans+=sum[1]
5號:
此時,tot[1]=3,sum[1]=2,h[1]=4,now=3
因爲在4號和5號之間沒有小於p的客棧,此時,不更新sum[1],也就是說,sum[1]還是2,5號對答案的貢獻就是5號與之前已經與後面客棧形成方案的顏色爲黑的客棧,也就是1號和2號,也就是sum[1]的值

代碼:

#include<iostream>
#include<cstdio>
using namespace std;

const int maxn=100+10;
int ans,now,n,k,p;
int h[maxn],tot[maxn],sum[maxn];

int main()
{
    scanf("%d%d%d",&n,&k,&p);
    for(int i=1;i<=n;++i)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        if(y<=p) now=i;//不要忘了等號 
        if(h[x]<=now) sum[x]=tot[x];//等號!! 
        h[x]=i;
        ans+=sum[x];
        tot[x]++;
    }
    printf("%d",ans);
    return 0;
}
發佈了77 篇原創文章 · 獲贊 2 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章