• CF939F Cutlet (单调队列优化DP)


    题目大意:要煎一块有两个面的肉,只能在一段k不相交的时间段$[l_{i},r_{i}]$内翻转,求$2*n$秒后,保证两个面煎的时间一样长时,需要最少的翻转次数,$n<=100000$,$k<=100$

    神仙单调队列优化$DP$, [NOI2005]瑰丽华尔兹 也有类似的压时间段的套路,但这道题可比那道题难多了。

    朴素$O(n^2)$的$DP$没什么好说的,我们要想办法把它优化成$O(nk)$的

    定义$f[i][j]$表示第$i$个时间段内,朝上的面(现在没被煎的)被煎的时间是$j$

    1.观察翻转的过程,貌似在一个连续的时间段内翻转2次以上就是没有意义的 ,因为可以翻过去再翻回来

    2.貌似并不一定要在整数时间翻转,但这种情况只在翻转1次的情况下有意义,所以整体把时间*2

    然后,分情况讨论$DP$转移

    1.翻0次,朝上的面被煎的时间不变,$f[i][j]=f[i-1][j]$,无需任何优化

    2.翻2次,朝上的面被至多额外煎$r_{i}+l_{i}$秒,枚举上一次当前面被煎的时间$k$,可得$f[i][j]=min(f[i][k])+2;(k<=j)$

    对于这种情况,正序枚举$j$,单调队列优化$DP$即可,$j-k>r_{i}+l_{i}$的弹出队列

    3.翻1次,原来朝上的面被翻到了下面,设现在的上面是$a$面,下面是$b$面,则$a$面被煎了$j$秒,$b$面被煎了$r_{i}-j$秒

    那么上一次$a$面被煎的时间是$k$,此时$a$面朝下,朝上的面是$b$面,被煎的时间是$r_{i-1}-k$,可得$f[i][j]=min(f[i-1][r_{i}-k])+1$

    因为是$-k$,要倒序枚举$j$,同样用单调队列优化,$k-j>r_{i}+l_{i}$弹出队列即可

    虽然空间能开下$O(nk)$,但用滚动数组跑得飞快

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #define N 205
     5 #define M 401000
     6 #define dd double
     7 #define inf 0x3f3f3f3f
     8 #define rint register int 
     9 using namespace std;
    10 
    11 int n,K,cnt;
    12 int l[N],r[N],t[N];
    13 int f[2][M],que[M];
    14 
    15 int main()
    16 {
    17     scanf("%d%d",&n,&K);
    18     for(int i=1;i<=K;i++){
    19         scanf("%d%d",&l[i],&r[i]);
    20         t[++cnt]=l[i]<<1,t[++cnt]=r[i]<<1;
    21     }
    22     memset(f,0x3f,sizeof(f));
    23     f[0][0]=0;int now=1,pst=0;
    24     n<<=1;
    25     for(int i=1;i<=cnt;i++)
    26     {
    27         if(i&1) continue;
    28         int hd=1,tl=0;
    29         for(rint j=0;j<=t[i];j++)
    30             f[now][j]=inf;
    31         for(rint j=0;j<=t[i];j++)
    32         {
    33             f[now][j]=min(f[now][j],f[pst][j]);
    34             while(hd<=tl&&f[pst][j]<=f[pst][que[tl]])
    35                 tl--;
    36             que[++tl]=j;
    37             while(hd<=tl&&j-que[hd]>t[i]-t[i-1])
    38                 hd++;
    39             f[now][j]=min(f[now][j],f[pst][que[hd]]+2);
    40         }
    41         hd=1,tl=0;
    42         for(rint j=t[i];j>=0;j--)
    43         {
    44             while(hd<=tl&&f[pst][t[i]-j]<=f[pst][t[i]-que[tl]])            
    45                 tl--;
    46             que[++tl]=j;
    47             while(hd<=tl&&que[hd]-j>t[i]-t[i-1])
    48                 hd++;
    49             f[now][j]=min(f[now][j],f[pst][t[i]-que[hd]]+1);
    50         }
    51         swap(now,pst);
    52     }   
    53     if(f[pst][n]==inf) printf("Hungry
    ");
    54     else printf("Full
    %d
    ",f[pst][n]);
    55     return 0;
    56 }
  • 相关阅读:
    【HDU 2507】【ACM-ICPC算法基础训练教程 题1-6】 迷瘴(贪心)
    【算法】Floyd-Warshall算法(任意两点间的最短路问题)(判断负圈)
    【读书笔记】2015年考研英语二真题翻译(帮你克服艰难之路的真理+熟路效应)
    visio给任意图形进行填充
    scanf清除缓存区
    macbook安装并破解Clion2018(Pycharm也一样)
    mac电脑对ntfs格式硬盘进行写操作(简单说就是向ntfs硬盘拷贝东西)
    查找mac下腾讯视频下载地址
    PyQt5初级教程(一)
    迷途指针
  • 原文地址:https://www.cnblogs.com/guapisolo/p/9903551.html
Copyright © 2020-2023  润新知