1. 程式人生 > >美團:優惠券(set+思維)

美團:優惠券(set+思維)

美團點評上有很多餐館優惠券,使用者可以在美團點評App上購買。每種優惠券有一個唯一的正整數編號。每個人可以擁有多張優惠券,但每種優惠券只能同時擁有至多一張。每種優惠券可以在使用之後繼續購買。

當用戶在相應餐館就餐時,可以在餐館使用優惠券進行消費。某人優惠券的購買和使用按照時間順序逐行記錄在一個日誌檔案中,運營人員會定期抽查日誌檔案看業務是否正確。業務正確的定義為:一個優惠券必須先被購買,然後才能被使用。

某次抽查時,發現有硬碟故障,歷史日誌中有部分行損壞,這些行的存在是已知的,但是行的內容讀不出來。假設損壞的行可以是任意的優惠券的購買或者使用。

現在給一個日誌檔案,問這個日誌檔案是否正確。若有錯,輸出最早出現錯誤的那一行,即求出最大s,使得記錄1到s-1滿足要求;若沒有錯誤,輸出-1。


輸入描述:
輸入包含多組資料

m 分別表示 m (0 ≤ m ≤ 5 * 10^5) 條記錄。

下面有m行,格式為:

I x (I為Input的縮寫,表示購買優惠券x);

O x(O為Output的縮寫,表示使用優惠券x);

? (表示這條記錄不知道)。

這裡x為正整數,且x ≤ 10^5 。


輸出描述:
-1 或 x(1 ≤ x ≤ m) 其中x為使得1到x-1這些記錄合法的最大行號。

輸入例子:
0
1
O 1
2
?
O 1
3
I 1
?
O 1
2
I 2
O 1

輸出例子:
-1
1
-1
-1

2

思路:

這道題一開始覺得很簡單,用cnt記錄?的次數,然後遇到不合法的資料就判斷下cnt就行了,後面發現還是太天真了,too young,測了一組資料? ? O 1 O 1 發現輸出的是-1,顯然不是的嘛,所以發現自己的思維存在漏洞,其實剛開始考慮的時候沒有注意到?所能變換的限制,我是把他當做任意值來處理,並沒有考慮到?變化的時候並不能使他變化為已經存在的操作。。。想到了這個問題,想了好久,不知道怎麼處理 自己還是太菜,唉。。問了大神,才知道還有這種操作:其實我們可以這樣去考慮問題,不再是去考慮?可以變成什麼,而是去考慮當非問號操作的時候,是否合法,那麼該怎樣去判斷,我們去分析每一個操作,其實操作是否合法,當前優惠卷操作只跟上一次對這種操作有關,當購買操作的時候,如果之前沒進行過這種優惠券的操作或者之前的是用掉這種優惠卷,那麼就直接購買,如果之前買了這種優惠卷那麼就要用到?了,那麼怎麼去判斷呢,對於上一次對這種優惠卷的操作是買入,那麼這一次還是買入,首先對於之前的?操作都不用管,為什麼呢, 因為之前的?操作對上一次買入操作到這一次的買入操作,是沒有影響的了,因為之前的?如果是當做買入操作,那麼就早就是不合法操作了,如果是賣出,更加不用管了。所以我們只用考慮上一次對這種的操作和這一次對這種的操作之間的?號,如果有?號就取第一個?並且視為合法操作,然後之後需不考慮這個?為什麼要取第一個呢,因為這樣就防止把後面的別人需要的拿走了,而後面的又拿不到你前面的?操作。但操作是賣出操作的是時候需要用到?的情況就只有上一次對這個操作也是賣出操作,或者之前沒有出現這種情況。這時候和買入操作一樣去找之間的?

接下來就是怎麼實現的了,我們把?號出現的位置也就是下標丟到set裡面,然後用每一次操作的位置去查詢,找到第一個>的位置,如果能找到,就刪掉這個?,不能找到就記錄位置,還有一個問題,怎麼記錄上一個操作的位置,很簡單開個陣列記錄每一種優惠卷的位置就行了,當更新的時候,先去判斷再去更新就行了,記得賣出操作的時候記錄負的,不然怎麼知道上一個操作是買還是賣。

ac程式碼:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<set>
#include<iostream>
#include<sstream>
using namespace std;
const int maxn = 1e5+100;
int num[maxn*5];
int n;
int main()
{
    char s[10];
    while(~scanf("%d",&n))
    {
        set<int>Q;
        int ans ;
        int ok = 0;
        set<int>::iterator it;
        for(int i = 0 ;i<n;i++)
        {
            scanf("%s",s);
            if(s[0]=='?')
            {
                Q.insert(i+1);
            }
            else if(s[0]=='I')
            {
                int tmp;
                scanf("%d",&tmp);
                if(ok)
                    continue;
                if(num[tmp]>0)
                {
                    it = Q.lower_bound(num[tmp]);
                    if(it!=Q.end())
                    {
                        Q.erase(it++);
                    }
                    else
                    {
                        if(ok==0){
                        ok=1;
                        ans=i+1;
                        }
                    }
                }
                num[tmp] = i+1;
            }
            else
            { int tmp;
                scanf("%d",&tmp);
                if(ok)
                    continue;
                if(num[tmp]<=0)
                {
                    it = Q.lower_bound(-num[tmp]);
                    if(it!=Q.end())
                    {
                        Q.erase(it++);
                    }
                    else
                    {
                        if(ok==0){
                        ok=1;
                        ans=i+1;
                        }
                    }
                }
                num[tmp] =-(i+1);

            }
        }
        if(ok)
        {
            cout<<ans<<endl;
        }
        else
        {
            cout<<-1<<endl;
        }
    }
}