首页 > 其他分享 >P5017题解

P5017题解

时间:2024-03-07 13:34:45浏览次数:20  
标签:状态 int 题解 时间 P5017 等待时间 转移 dp

前言

做这道题,首先要了解 \(dp\)。\(dp\) 一般有三个步骤(个人理解):

  1. 根据题意确定状态。
  2. 根据状态的定义推出状态转移方程,一般有两种:填表法和刷表法。填表法就是普通 \(dp\),用前面的状态转移到现在的状态,例:\(f[i]=f[i-1]+a[i]\)。刷表法就是在现有的基础上(\(f[i]\) 已知),去推出 \(f[k]\)(\(k>i\)),例:\(f[i+1]=f[i]+a[i]\)。
  3. 处理边界并输出。边界问题是 \(dp\) 中非常重要的部分,且每道题的边界不同,要视题意而定。

注:此题采用刷表法。


暴力

对于每道题,首先考虑暴力。那么这道题呢,首先你必须想到的就是需要排序,毕竟排序后车子在每个时间段接的人你才能知道。排完序后,试着用 \(f[i]\) 表示前 \(i\) 个人都被接走得最小等待时间。

试着推状态转移方程:\(f[k]=f[i]+T(k>i)\),那么 \(T\) 等于 \(i+1\) ~ \(k\) 的总等待时间,这里补充一下 \(T\) 怎么算:\(T=l*(k-i)-(t[k]-t[i])\),\(l\) 是 \(k\) 被接走的时间,\(t\) 是前缀和数组,这个公式不理解没关系,请继续看下去(这是 \(dp\) 的状态转移方程,在正解里我会解释)。因为我们要用到 \(l\),但是我们并不知道 \(k\) 是什么时候被接走的(也就是不知道 \(l\)),所以我们就无法算出 \(T\)。

当我们发现一维不行时,就定义二维状态转移方程。根据一维的推导过程中发现,是因为我们不知道 \(k\) 是什么时候被接走的,才失败的。所以第二维果断定义为时间:\(f[i][j]\) 表示前 \(i\) 个人在 \(j\) 时刻全被接走。那么我们现在就可以算出来 \(f[i][j]\) 了。但是我们发现第二维是 \(4*10^6\),空间和时间都爆了,但是可以拿 \(50\) 分,不推荐。

正解

我们现在的问题是第二维,那么我们考虑优化第二维:细心观察数据发现,\(n,m\) 都比较小,所以用他们来定义状态转移方程。再多想一点,我们发现:\(f[i][j-m]\) 以下的状态都对 \(f[i][j]\) 这个状态没有影响。为什么呢?原因很简单,\(f[i][j-m]\) 这个状态是随着前一次车子走的,而 \(f[i][j]\) 是随着这一次的车子走的(车子 \(m\) 分钟来回一次)。

所以我们不妨优化定义:\(f[i][j]\) 表示第 \(i\) 个人等了 \(j\) 分钟后前 \(i\) 个人全上车的最小等待时间。

那么状态转移方程就是:\(f[k][l]=f[i][j]+T\)。其中 \(l\) 表示第 \(k\) 个人的等候时间。\(T\) 表示 \(i+1\) ~ \(k\) 这段区间内所有人的等候时间总和。所以我们现在的问题就变成了求 \(l\) 和 \(T\)。

  1. 先看 \(l\):\(l\) 表示的是第 \(k\) 个人的等候时间,且由 \(i\)转移而来,所以 \(l\) 等于 \(i\) 的上车时间加上车子的往返时间减去自己到达的时间(这里一定要弄懂),\(i\) 的等候时间就是 \(a[i]+j\),\(a\) 数组表示 \(i\) 到达的时间,\(j\) 是 \(i\) 等待时间,所以 \(l=a[i]+j+m-a[k]\),其中 \(a[i]+j+m\) 就是车子在送完 \(i\) 后回到起点的时间,用这个时间减去 \(k\) 到达的时间,不就是 \(k\)的等候时间吗?

  2. 再看\(T\):\(T\) 表示 \(i\)~\(k\) 这段区间内所有人的等候时间总和。这个也很好想,考虑一个事实,\(总的等待时间=结束时间*人数-这些人到达时间的和\)。比如:结束时间为 \(5\) ,有两个人,他们到达时间为 \(3,4\),最后的等待时间就是 \(5*2-(3+4)=3\)。那么这道题的结束时间就是 \(a[k]+l\),就是到达时间(\(a[k]\))加上等候时间(\(l\)),人数就是(\(k-i\)),他们等待时间之和可以用前缀和算出来,就是 \(t[k]-t[i]\),\(t\) 是前缀和数组。那么这道题也就完了呢。

  3. 状态转移方程:\(f[k][l]=min(f[k][l],f[i][j]+(a[k]+l)*(k-i)+(t[k]-t[i]))\)。

  4. 边界问题:先初始化为了正无穷,\(f[0][0]\) 为 \(0\)。

  5. 细节问题看代码。

AC code

#include<bits/stdc++.h>
#define int long long
#define x first
#define y second
using namespace std;
typedef pair<int,int> pii;
const int N=510,M=110;
int inf;
int n,m;
int f[N][M];
int a[N],t[N];
signed main(){
    memset(f,0x3f,sizeof f);
    inf=f[0][0],cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++) t[i]=t[i-1]+a[i];
    f[0][0]=0,a[0]=-inf;
    for(int i=0;i<=n;i++){
        int M=min(m-1,a[i+1]-a[i]);
		//优化时间和空间,j只用枚举到m-1,因为前面的数会跟着前面的车走
		//a[i+1]-a[i]表示这个点到下一个点的时间差,因为一旦与下一个点的距离不大于m-1,就可以同时乘坐同一次车 
        for(int j=0;j<=M;j++){
            if(f[i][j]==inf) continue; 
            for(int k=i+1;k<=n;k++){
                int l=max(a[i]+j+m-a[k],0ll);//等待时间 
                f[k][l]=min(f[k][l],f[i][j]+(a[k]+l)*(k-i)-(t[k]-t[i]));
                //状态转移方程式 
            }
        }
    }
    int ans=inf;
    for(int i=0;i<m;i++) ans=min(ans,f[n][i]);//最后取值 
    cout<<ans<<endl;
    return 0;
}/*
f[i][j]表示前i个人等了j时刻上车时的最小等候时间(滚动数组,降低时间与空间复杂度)
f[k][l]=min(f[k][l],f[i][j]+(t[k]+l)*(k-i)-(t[k]-t[i]));
*/

\[Thanks \]

标签:状态,int,题解,时间,P5017,等待时间,转移,dp
From: https://www.cnblogs.com/Celestial-cyan/p/18058697

相关文章

  • SP20848 IGAME - Interesting Game 题解
    分析数位DP一眼题。对于一个\(k\)位的数\(s\),我们不妨将其看做由数字\(s_1,s_2,s_3,\dots,s_k\)这\(k\)个数字拼接起来的。而题意是每个人可以将\(s_1,s_2,s_3,\dots,s_k\)中的任意一个减去任意数字,保证不减去\(0\)且结果\(\ge0\)。显然,在我们将这\(k\)个数看......
  • AT_abc216_g [ABC216G] 01Sequence 题解
    分析一道差分约束题。我们令\(\mathit{sum}_{i}\)表示\(1\)到\(i\)中,\(1\)的数量,根据题意可得:\(\mathit{sum}_{l_i-1}+x_i\le\mathit{sum}_{r_i}\)\(\mathit{sum}_{l+1}+(-1)\le\mathit{sum}_{l}\)\(\mathit{sum}_{l}+0\le\mathit{sum}_{l+1}\)因为我们要尽......
  • CF1066E 题解
    Solution首先不难想到计算\(a\)的每一位对答案产生的贡献,然后题目告诉我们\(b\)每次会往右移一位,然后结合样例可以发现:对于\(a\)的第\(i\)位,能与其产生贡献的条件是:\(a_i=1\)且\(b_j=1(i\leqj)\),对答案的贡献不难想出即为\(2^{i-1}\times\sum\limits_{j=i}^{m}b_j......
  • AT_abl_e Replace Digits 题解
    分析线段树模板题。维护一个区间\([l,r]\)中\(\sum\limits_{i=l}^r10^{n-i}\)的答案。将某个区间\([l,r]\)全部修改成\(x\)之后的表示的数就是\(x\times(\sum\limits_{i=l}^r10^{n-i})\)。区间修改可以用线段树,用快速幂或者预处理弄出来\(10^x\),建树的时候就能把每......
  • AT_abl_d Flat Subsequence 题解
    分析线段树模板题。一眼DP。定义状态函数\(\mathit{f}_i\)表示前\(i\)个数中,必选\(\mathit{A}_i\)时\(B\)的最大长度。则有转移方程:\(\mathit{f}_i=\max\{f_j|((1\lej\lei-1)\land(-k\leA_i-A_j\lek))\}+1\)。答案就是\(\max\limits_{i=1}^{n}\mathit{f}_i......
  • CF808E 题解
    很好的一道分类讨论题。观察数据范围,\(w\leq3\),不难想到,将\(w\)分为\(1,2,3\)种情况,如果直接贪心选会不难发现是错的。但是如果\(w\)的值只有\(2\)种,就像\(w=1/2\)的情况,将\(w=1/2\)的数据按价值排序,最后枚举每种选多少即可。但是\(w=3\)就会显得难以处理,需要讨......
  • CF1824B1 LuoTianyi and the Floating Islands (Easy Version) 题解
    分析按照\(k\)的奇偶分开考虑。\(k\)为奇数。一个好的节点有且仅有一个在任意两个有人的节点\(i,j\)的路径的交点上的最优位置。若该交点偏移\(1\)步,则必然会使路径长度和\(+1\)。故期望为\(1\)。\(k\)为偶数。任意一个好的节点仍然在任意两个有人的节点\(i,j\)的......
  • 【教程】HBuilderX开发实践:隐私合规检测问题解决方案
    文章目录摘要引言正文1、违规收集个人信息2、APP强制、频繁、过度索取权限知识点补充总结 摘要本篇博客介绍了在使用HBuilderX进行开发过程中,常遇到的隐私合规问题,并提供了相应的解决方案。主要包括违规收集个人信息和APP强制、频繁、过度索取权限两方面。......
  • CF147B 题解
    Solution一道十分典型的dp题。有三个关键点分别是定义状态、优化和答案的统计。首先定义状态,定义\(f_{i,j,p}\)表示\(i\toj\)号节点,共走了不超过\(p\)条边,且是\(i\toj\)的最长路径。不超过\(p\)条边是为了方便转移,而最长路径如果都为负环,说明需要走更多的边,实......
  • P1503 鬼子进村 题解
    分析分块。我们定义\(\mathit{cnt}_i\)表示房子\(i\)是否出现过,\(\mathit{sum}_i\)表示在第\(i\)个块内没有被摧毁的房子数量,维护的房子是\((i-1)\timesS-1\)到\(i\timesS\),其中\(S=\sqrt{n}\)也就是块长。操作\(1\)。写一个栈,根据后进先出的特点,讲摧毁的房子......