【DP专题】——[USACO13OPEN]照片Photo

这道题是道非常好的动规题,不难但思考过程受益很大。

[9/25日更新:鸽了俩个月回来补档了]

题目描述

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”。

输入输出格式

输入格式:

* 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.

我们看到题目中有个很重要的条件:“每张照片中都有且仅有一只身上带有斑点的奶牛”。

一:用f[i]表示选第i头牛时最大牛数,假设f[i]是由某个j转移过来

1.区间最多只有一头:

  考虑这个情况,则j必须在i所在的所有区间中最左的那个端点之前,记为j<=r[i],r[i]表示i所在所有区间的最左端点;

2.区间最少只有一头:

  考虑这个情况,则i覆盖的所有区间中,除i这个位置以外都不能放牛,所以极有可能使得在i左方的某一个区间被i所在的某一个区间覆盖或者相交的情况,考虑最近的那个,即所有 区间范围在i左侧的区间 中左端点最靠近i(即最大)的那个点,记为l[i],有j>=l[i]。

  综上,我们得出f[i]=max{f[j]+1,l[i]<=j<=r[i]}。

二:我们考虑如何维护l与r:

  输入区间的时候,设区间为[a,b],可以确定在b这个点,有一点a-1可以确定为b的一个左值(但不知道是否为最左的那个),暂且记为r[b]=a-1。同理,对于点b+1,a也有可能是它的一个右值(也是暂定),记为l[b+1]=a。

  而我们知道,一个区间最小不会小于只包含一个数字,所以考虑r[i],还可以提前一步令r[i]=i-1,总之取最小值就可以了;

  

现在我们去求是否有更优答案:

   对于一个点i,和i+1,我们知道,如果一个区间右端为i+1,那么这个区间有两个可能:

1.不过i 这个时候区间就是一个数,r[i+1]=i。

2.过i 这个时候,r[i+1]有可能比r[i]还小。

综上两点,其实只要取r[i]=min{r[i],r[i+1]}即可。(情况1根本不用考虑好吗。。。)

l[i]类似,在此不做赘述,l[i]=max{l[i],l[i-1]}。

  接着我们用单调队列来处理这个东西:

  我们在l[i]到r[i]的范围内,找到最大的f[x]更新。

参考了一下大佬的代码,这里有一些小细节:比如可以用n+1来表示是否有解,单调队列的写法等。

#include<bits/stdc++.h>
using namespace std;
int read(){
    int x=0,f=1;
    char c=getchar();
    while(!isdigit(c)){
        if(c==‘-‘) f=-1;
        c=getchar();
    }
    while(isdigit(c)){
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return x*f;
}
const int N=2e5+10;
int n,m;
int l[N],r[N],f[N],q[N];
struct cow{
    int a,b;
}t[N];
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++){
        t[i]=(cow){read(),read()};
        l[t[i].b+1]=max(l[t[i].b+1],t[i].a);
        r[t[i].b]=min(r[t[i].b],t[i].a-1);
    }
    for(int i=n;i>=1;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]);
    }
    int head=1,tail=1;
    int pos=1;
    for(int i=1;i<=n+1;i++){
        while(pos<=r[i]&&pos<=n){
            if(f[pos]==-1){
                pos++;
                continue;
            }
            while(head<=tail&&f[pos]>f[q[tail]]) tail--;
            q[++tail]=pos;
            pos++;
        }
        while(head<=tail&&q[head]<l[i]) head++;
        if(head<=tail) f[i]=f[q[head]]+(i!=n+1?1:0);
        else f[i]=-1;
    }
    printf("%d",f[n+1]);
    return 0;
}

原文地址:https://www.cnblogs.com/Nelson992770019/p/11179109.html

时间: 2024-10-01 00:47:22

【DP专题】——[USACO13OPEN]照片Photo的相关文章

[USACO13OPEN]照片Photo [动态规划 单调队列]

[USACO13OPEN]照片Photo 这题好烧脑... #include<bits/stdc++.h> using namespace std; #define ll long long #define rg register #define Max(x,y) ((x)>(y)?(x):(y)) #define Min(x,y) ((x)>(y)?(y):(x)) const int N=2e5+5,M=1e5+5,inf=0x3f3f3f3f,P=19650827; int

P3084 [USACO13OPEN]照片Photo (dp+单调队列优化)

题目链接:传送门 题目: 题目描述 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

[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 r

P3084 [USACO13OPEN]照片Photo

题目描述 农夫约翰决定给站在一条线上的N(1 <= N <= 200,000)头奶牛制作一张全家福照片,N头奶牛编号1到N. 于是约翰拍摄了M(1 <= M <= 100,000)张照片,每张照片都覆盖了连续一段奶牛:第i张照片中包含了编号a_i 到 b_i的奶牛.但是这些照片不一定把每一只奶牛都拍了进去. 在拍完照片后,约翰发现了一个有趣的事情:每张照片中都有一只身上带有斑点的奶牛.约翰意识到他的牛群中有一些斑点奶牛,但他从来没有统计过它们的数量. 根据照片,请你帮约翰估算在他的

Luugu 3084 [USACO13OPEN]照片Photo

很神仙的dp...假装自己看懂了,以后回来复习复习... 设$f_{i}$表示从$1$到$i$,且$i$这个点必放的最小代价. 一个区间有两个限制条件:至少放一个,至多放一个. 因为一个区间至多要放一个,所以所有包含这个点的区间都不能再放,设$r_{i}$表示包含这个点的区间中最小的左端点$ - 1$. 因为一个区间至少要放一个,所以不能有区间中一个都不放,设$l_{i}$表示整个区间在当前点之前的最大的左端点. 这样子就有了转移方程:$f_{i} = max(f_{j}) + 1$  $(l_

【题解】[USACO] 照片Photo

[题解][USACO] 照片Photo [题目大意] 在\(1\)~\(N\)的序列上有\(M\)个区间,使得这\(M\)个小区间每个覆盖了且仅覆盖了一个点,求最多点数,如果无解,输出\(-1\). [分析] 刚开始做的时候我是懵的...不管三七二十一开始想差分约束系统,无奈没那么好的思维,没想出来... 一翻题解,,\(WOC!!!\)这是什么神仙\(DP?\)真的是学到了... 我们设\(f[i]\)表示序列的第\(i\)位是一个点时,序列\(1\)~\(i\)的最多点数. 那么\(dp\)

DP专题

DP专题 1. 背包模型 2. 子序列模型 3. 递推DP 4. 区间DP 5. 树形DP 6. 状压DP 学习资料:位操作基础篇之位操作全面总结 如何快速取得一个二进制状态的所有子状态 7. 概率DP 学习资料:简说期望类问题的解法 等等.......

[dp专题]hdu 1160 FatMouse&#39;s Speed

FatMouse's Speed Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 10172    Accepted Submission(s): 4521Special Judge Problem Description FatMouse believes that the fatter a mouse is, the faster i

数位dp 专题

数位dp 专题 先来模板: int dfs(int i,int s,bool e) ///枚举第i位,第i位前一位的数字为s,e表示前缀是否已达到上界.(如果未达到,则枚举0000...~9999..,反之枚举0000...~abcd...) { if(i==-1) return 1; if(!e&&~f[i][s]) return f[i][s];/// f记录的是位数为i,前一数字为s的0000..~9999...的符合条件的个数 int res=0; int u=e?num[i]:9