zoukankan      html  css  js  c++  java
  • [POJ 2373][BZOJ 1986] Dividing the Path

    Link:

    POJ 2373 传送门

    Solution:

    一开始想错方向的一道简单$dp$,不应该啊……

    我一开始的想法是以$cows' ranges$的节点为状态来$dp$

    但明显一个灌溉的区间的两边不一定都在$cows's ranges$上,

    因此应该以长为$L$的$field$上的每一个偶数节点为状态来$dp$,

    这样转移方程就很容易了:

    $dp[i]=min{ dp[j] } +1(2*ale i-jle 2*b)$

    由于$dp[j]$具有决策单调性(对于节点$i$,$k$比$j$更优$(j<k)$,那么对于后面任意一个节点$j$都优于$k$)

    于是使用单调队列维护一个$dp$值递增,离起点距离递增的序列,每次弹出$i-q[l]>=2*b$的$l$

    为了处理$cows' ranges$上的节点,使用差分将在区间内的节点打上标记,遇到时跳过即可

    Note:这里的特判依然要注意,如果对于一个非终点的节点找不到符合的点,不代表无解!跳过即可

    Code:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    const int MAXN=1e6+10;
    
    int n,L,a,b,dp[MAXN],pre[MAXN],q[MAXN],l,r;
    
    int main()
    {
        scanf("%d%d%d%d",&n,&L,&a,&b);
        for(int i=1;i<=n;i++)
        {
            int x,y;scanf("%d%d",&x,&y);
            pre[x+1]++;pre[y]--;
            if(y-x>2*b){printf("-1");return 0;}
        }
        for(int i=1;i<=L;i++) pre[i]+=pre[i-1];
        
        l=r=1;q[1]=0;
        for(int i=2*a;i<=L;i+=2)
        {
            if(pre[i]) continue;
            while(l<=r && i-q[l]>2*b) l++;
            if(l>r){printf("-1");return 0;}
            if(i-q[l]<2*a) continue; //对不符合条件的数的处理
            
            dp[i]=dp[q[l]]+1;
            while(l<=r && dp[i]<dp[q[r]]) r--;q[++r]=i; 
        }
        if(!dp[L]) printf("-1"); //特例处理 
        else printf("%d",dp[L]);
        return 0;
    }

    Review:

    (1)还是要对特判细节想清楚啊……

    (2)对于有决策单调性的题目想到单调性优化

    (3)选择$dp$状态时要考虑状态集是否包含了所有“过程”中的“终点”

    (如果按$cows' ranges$选取则不能)

  • 相关阅读:
    暴力+前缀和——cf1335E
    【经典】区间dp——cf1336E
    简单几何+并查集 —— 2015NAQ K
    spring mvc 文件上传 和 异常页面处理
    ajax 入门
    Codeforces Round #558 (Div. 2)
    [SDOI2019]热闹又尴尬的聚会(图论+set+构造)
    [SDOI2019]移动金币(博弈论+阶梯Nim+按位DP)
    [ZJOI2019]浙江省选(半平面交)
    [ZJOI2019]开关(生成函数+背包DP)
  • 原文地址:https://www.cnblogs.com/newera/p/9157388.html
Copyright © 2011-2022 走看看