1. 程式人生 > >bzoj 3126: [Usaco2013 Open]Photo——單調隊列優化dp

bzoj 3126: [Usaco2013 Open]Photo——單調隊列優化dp

mic closed last %d 區間 ble scrip 多少 得到

Description

給你一個n長度的數軸和m個區間,每個區間裏有且僅有一個點,問能有多少個點

Input

* Line 1: Two integers N and M.

* Lines 2..M+1: Line i+1 contains a_i and b_i.

Output

* Line 1: The maximum possible number of spotted cows on FJ‘s farm, or -1 if there is no possible solution.

Sample Input

5 3
1 4
2 5
3 4

INPUT DETAILS: There are 5 cows and 3 photos. The first photo contains cows 1 through 4, etc.

Sample Output

1
OUTPUT DETAILS: From the last photo, we know that either cow 3 or cow 4 must be spotted.
By choosing either of these, we satisfy the first two photos as well. —————————————————————————————————— 我們用f[i]表示選i這個位置放置特殊點的最優解 那麽我們發現每個點可以選擇的範圍是一個區間 並且容易證明這個區間是隨著位置的增加而右移也就是單調遞增的 因為你選擇了這個點 那麽包含這個點的所有區間都不能再加點了
所以r【i】=min(包含i的區間的左端點-1) 因為每個區間都要有點所以l【i】=完整在i左邊的區間中左端點的max 這樣我們就得到了每個點的轉移區間 這樣完美符合單調隊列的性質 所以就可以寫了 技術分享
#include<cstdio>
#include<cstring>
#include<algorithm>
using std::min;
using std::max;
const int M=250007,inf=0x3f3f3f3f;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<0||c>
9){if(c==-) f=-1; c=getchar();} while(c>=0&&c<=9){ans=ans*10+(c-0); c=getchar();} return ans*f; } int n,m,x,y; int l[M],r[M],f[M]; int q[M],ql=1,qr; int main(){ n=read(); m=read(); for(int i=1;i<=n+1;i++) r[i]=i-1; for(int i=1;i<=m;i++){ x=read(); y=read(); r[y]=min(r[y],x-1); l[y+1]=max(l[y+1],x); } for(int i=n;i;i--) r[i]=min(r[i],r[i+1]); for(int i=2;i<=n+1;i++) l[i]=max(l[i],l[i-1]); f[qr=1]=0; for(int i=1;i<=n+1;i++){ for(int k=r[i-1]+1;k<=r[i];k++){ while(ql<=qr&&f[q[qr]]<=f[k]) qr--; q[++qr]=k; } while(ql<=qr&&q[ql]<l[i]) ql++; if(ql>qr) f[i]=-inf; else f[i]=f[q[ql]]+1; } if(f[n+1]>=0) printf("%d\n",f[n+1]-1); else printf("-1\n"); return 0; }
View Code

bzoj 3126: [Usaco2013 Open]Photo——單調隊列優化dp