1. 程式人生 > 實用技巧 >BZOJ-1293 [SCOI2009]生日禮物(尺取法)

BZOJ-1293 [SCOI2009]生日禮物(尺取法)

題目描述

  彩珠有 \(1\leq n\leq 10^6\) 個,分為 \(1\leq k\leq 60\) 種。可以將綵帶考慮為 \(x\) 軸,每一個彩珠有一個對應的座標(即位置)。某些座標上可以沒有彩珠,但多個彩珠也可以出現在同一個位置上。剪一段綵帶,能包含所有種類的彩珠,同時使綵帶儘可能短,求最短的長度。

分析

  記錄每個彩珠的顏色和位置,按位置從小到大排序,尺取法,右指標右移的時候記錄顏色 \(i\) 出現了 \(tot[i]\) 次,記錄當前不同顏色數 \(sum\)\(sum=k\) 時左指標右移,刪去對應顏色出現的次數和不同顏色數。

程式碼

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x*f;
}
const int N=1e6+10;
const int INF=0x3f3f3f3f;
struct node
{
    int pos;
    int ID;
}a[N],temp[N];
int tot[N];
bool cmp(node A,node B)
{
    return A.pos<B.pos;
}
int main()
{
    int n,k,cnt=0;
    cin>>n>>k;
    for(int i=1;i<=k;i++)
    {
        int x=read();
        for(int j=1;j<=x;j++)
        {
            cnt++;
            a[cnt].pos=read();
            a[cnt].ID=i;
        }
    }
    sort(a+1,a+1+cnt,cmp);
    int ans=INF;
    int l=1,r=0,sum=0;
    for(int i=1;i<=n;i++)
    {
        r++;
        temp[r].pos=a[i].pos;
        temp[r].ID=a[i].ID;
        tot[a[i].ID]++;
        if(tot[a[i].ID]==1)
            sum++;
        while(sum==k)
        {
            ans=min(ans,temp[r].pos-temp[l].pos);
            tot[temp[l].ID]--;
            if(tot[temp[l].ID]==0)
                sum--;
            l++;
        }
    }
    cout<<ans<<endl;
    return 0;
}