照片 usaco 2013 open photo

題目

Farmer John決定爲他的N頭排列好的奶牛(1 <= N<= 200,000)做一張全景合照。這N頭奶牛分別以1..N進行編號。他一共拍了M(1<= M <=100,000)張相片,每張相片都只包含有一部分位置連續的奶牛:第i張照片涵蓋着編號從a_i到b_i的所有奶牛。當然,這些照片合起來並不保證包含所有的牛。

Farmer John拍攝完所有的相片後,注意到一個很有趣的現象:他拍的每張照片中有且僅有一隻奶牛身上有斑點。 FJ知道他的奶牛中有一部分是身上有斑點的,但他從來沒有數過這種奶牛的數目。請根據FJ的這些照片,確定可能出現的斑點牛的最大的數目;若從FJ的照片中無法推測斑點牛的數目,則輸出-1。

​1 <= N<= 200,000

分析

這道題,要畫畫圖理解才行。
其實就是要求
1.在每個區間裏面都必須要有一個牛有斑點。
2.並且每個區間裏面都必須只有一個牛有斑點
這兩句話很關鍵。
於是我們可以根據這兩個條件做dp。
首先我們設f[i]爲前i個牛滿足條件且最多能有多少牛有斑點,便有f[i]=max(f[j])+1
那麼j的範圍呢?
根據條件1,我們可以確定左邊界
(因爲必須選,那麼上一個區間也一定要選,故j一定是>=最靠近i左邊的區間的左座標)
根據條件2,我們可以確定右邊界。
(因爲必須選一個,所以包含i的區間裏面的任意一個j都不能轉移,即j<=包含i的區間的最小的左座標)
故我們可以根據這些限定用單調隊列來優化原來的dp方程。

不得不說,這道題的思路確實很巧妙,竟能轉換成dp,orz orz

#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int N=200005;
struct pop{
    int x,y;
}a[N];
int n,m,st[N],en[N],f[N],q[N];
bool cmp(pop a,pop b){
    return a.y<b.y;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) scanf("%d%d",&a[i].x,&a[i].y);
    sort(a+1,a+1+m,cmp);
    int mat=0;
    for(int i=1,j=1;i<=n;i++){
        while (a[j].y<i&&j<=m) mat=max(mat,a[j].x),j++;
        st[i]=mat;
    }st[n+1]=st[n];
    int mie=N+1;en[n+1]=n+1;
    for(int i=n,j=m;i;i--){
        while (a[j].y>=i&&j<=m) mie=min(mie,a[j].x),j--;
        en[i]=mie;
    }
    int l=1;int r=0;
    for(int i=1,j=0;i<=n+1;i++){
        for(;j<en[i]&&j<i;j++){
            if (f[j]<0) continue;
            while (l<=r&&f[q[r]]<f[j]) r--;
            q[++r]=j;
        }
        while (l<=r&&q[l]<st[i]) l++;
        if (l<=r&&f[q[l]]!=-1) f[i]=f[q[l]]+(i!=n+1);else f[i]=-1;
    }
    printf("%d",f[n+1]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章