[USACO13OPEN]照片Photo

题目描述

Farmer John has decided to assemble a panoramic photo of a lineup of his N cows (1 <= N <= 200,000), which, as always, are conveniently numbered from 1..N. Accordingly, he snapped M (1 <= M <= 100,000) photos, each covering a contiguous range of cows: photo i contains cows a_i through b_i inclusive. The photos collectively may not necessarily cover every single cow.

After taking his photos, FJ notices a very interesting phenomenon: each photo he took contains exactly one cow with spots! FJ was aware that he had some number of spotted cows in his herd, but he had never actually counted them. Based on his photos, please determine the maximum possible number of spotted cows that could exist in his herd. Output -1 if there is no possible assignment of spots to cows consistent with FJ's photographic results.

农夫约翰决定给站在一条线上的N(1 <= N <= 200,000)头奶牛制作一张全家福照片,N头奶牛编号1到N。

于是约翰拍摄了M(1 <= M <= 100,000)张照片,每张照片都覆盖了连续一段奶牛:第i张照片中包含了编号a_i 到 b_i的奶牛。但是这些照片不一定把每一只奶牛都拍了进去。

在拍完照片后,约翰发现了一个有趣的事情:每张照片中都有且仅有一只身上带有斑点的奶牛。约翰意识到他的牛群中有一些斑点奶牛,但他从来没有统计过它们的数量。 根据照片,请你帮约翰估算在他的牛群中最多可能有多少只斑点奶牛。如果无解,输出“-1”。

Input

输入输出格式

输入格式:

* Line 1: Two integers N and M.

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

输出格式:

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

输入输出样例

输入样例#1: 
5 3 
1 4 
2 5 
3 4 
输出样例#1:
1 

说明

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

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.

题解

神仙般的dp……第一眼以为是差分约束……后来发现居然可以用dp乱搞……

用$f[i]$表示到第i个位置为止且第i个位置必放,最多能放多少个

因为有两个限制条件:每个区间至少一个,每个区间至多一个

因为一个区间至多一个,所以所有包含这个点的区间都不能再放,要找到所有包含这个点的区间中最小的左端点,令$r[i]=左端点-1$

因为一个区间至少一个,所以不能有地方空着不放,找到整个区间在当前点之前的区间,取最大的左端点,令$l[i]=左端点$

每一次读入的时候,用$x$更新$l[y+1]$用x-1更新$x-1$更新$r[y]$

然后正着扫一遍,用$l[i-1]$更新$l[i]$(在i-1之前的左端点必定在i之前);然后倒着扫一遍,用$r[i+1]$更新$r[i]$

所以$f[i]=max{f[j]+1,l[i]<=j<=r[i]}$,开个单调队列优化

 1 //minamoto
 2 #include<bits/stdc++.h>
 3 #define N 200005
 4 using namespace std;
 5 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<15,stdin),p1==p2)?EOF:*p1++)
 6 char buf[1<<15],*p1=buf,*p2=buf;
 7 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
 8 template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
 9 inline int read(){
10     #define num ch-'0'
11     char ch;bool flag=0;int res;
12     while(!isdigit(ch=getc()))
13     (ch=='-')&&(flag=true);
14     for(res=num;isdigit(ch=getc());res=res*10+num);
15     (flag)&&(res=-res);
16     #undef num
17     return res;
18 }
19 int n,m,l[N],r[N];
20 int h,t,q[N],f[N];
21 int main(){
22     //freopen("testdata.in","r",stdin);
23     n=read(),m=read();
24     for(int i=1;i<=n+1;++i) r[i]=i-1;
25     for(int i=1;i<=m;++i){
26         int x=read(),y=read();
27         cmin(r[y],x-1);
28         cmax(l[y+1],x);
29     }
30     for(int i=n;i>=1;--i) cmin(r[i],r[i+1]);
31     for(int i=2;i<=n+1;++i) cmax(l[i],l[i-1]);
32     int j=1;h=t=1,q[1]=0;
33     for(int i=1;i<=n+1;++i){
34         while(j<=r[i]&&j<=n){
35             if(f[j]==-1){++j;continue;}
36             while(f[j]>f[q[t]]&&h<=t) --t;
37             q[++t]=j;
38             ++j;
39             }
40         while(q[h]<l[i]&&h<=t) ++h;
41         if(h<=t) f[i]=f[q[h]]+(i!=n+1?1:0);
42         else f[i]=-1;
43     }
44     printf("%d
",f[n+1]);
45     return 0;
46 }
原文地址:https://www.cnblogs.com/bztMinamoto/p/9375444.html