codeforces939F Cutlet

本文探讨了一个有趣的时间优化问题,即如何在限定时间内通过最少的翻面次数,使两面肉均匀煎熟。采用动态规划方法,结合队列优化,解决了一个包含k个不相交时间区间的煎肉问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:有2*n的时间去煎一片肉,其中有k个不相交区间,在这些区间里可以翻面,求最后每面都煎n分钟的最小翻面次数。

有一个显而易见(exm???)的思路,设dp状态为dp[i][j]表示在第i分钟朝上的面煎了j分钟,

那么转移就是dp[i][j]=min(dp[i-1][j],dp[i-1][i-j]+1),就是上一秒不翻,或者上一秒翻了,并且之前向上的时间为j,现在就是i-j。

但是这显然超时,我们发现k≤100,可以把时间转换为区间,而且我们发现,对于一个区间,只有三种情况:

1.不翻转,直接继承dp[i][j]=dp[i-1][j]。

2.翻转一次,设当前朝上的面的时间为j,那么现在朝下的面的时间为r-j,设这段时间里现在朝下的面烤了k分钟,那么之前这面

就烤了r-j-k分钟,而这面就是翻面前的上面,所以dp[i][j]=dp[i-1][r-j-k]+1。

3.翻转两次,设当前朝上的面时间为j,这段时间烤的时间为k,那么之前烤的就是j-k分钟。所以dp[i][j]=dp[i-1][j-k]+2。

但是这仍然很慢,所以我们考虑队列优化。

对于翻转两次的情况,

\large \because k\leq r-l

\large \therefore -k\geq l-r

\large \therefore j-k\geq j+l-r

\large p=j-k

\large p\geq j+l-r

所以选择大于等于当前枚举时间+l-r的值作为更新,维护递增序列

对于翻转一次的情况,也是一样,不过因为条件是k\leqslant r-j所以为了更新,我们倒叙枚举,推入队列的为r-j。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int n,k;
int dp[105][100005];
int que[100005];
int main()
{
    scanf("%d%d",&n,&k);
    memset(dp,0x3f,sizeof(dp));dp[0][0]=0;
    for(int w=1;w<=k;w++)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        int head=1,tail=0;
        memcpy(dp[w],dp[w-1],sizeof(dp[w]));
        for(int i=0;i<=min(r,n);i++)
        {
            while(head<=tail&&dp[w-1][que[tail]]>=dp[w-1][i])tail--;
            while(head<=tail&&que[head]<i+l-r)head++;
            que[++tail]=i;
            dp[w][i]=min(dp[w][i],dp[w-1][que[head]]+2);
        }
        head=1,tail=0;
        for(int i=r;i>=max(r-n,0);i--)
        {
            while(head<=tail&&dp[w-1][que[tail]]>=dp[w-1][r-i])tail--;
            while(head<=tail&&que[head]<l-i)head++;
            que[++tail]=r-i;
            dp[w][i]=min(dp[w][i],dp[w-1][que[head]]+1);
        }
    }
    if(dp[k][n]==0x3f3f3f3f)
    {
        printf("Hungry");
        return 0;
    }
    printf("Full\n");
    printf("%d",dp[k][n]);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值