Luogu P9180 [COCI2022-2023#5] Slastičarnica 题解 [ 蓝 ] [ 区间 dp ] [ dp 状态优化 ] [ 前缀和优化 ]
Slastičarnica:非常好的区间 dp 题。
暴力
不难设计出暴力状态:\(dp_{q,i,j}\) 表示进行到第 \(q\) 次操作,剩下区间 \([i,j]\) 是否可行。
直到全部状态都为 \(0\) 的时候输出即可。
期望得分 \(19pts\)。
优化(假)
观察到每个 \(dp\) 状态都只有两个值 \(0,1\),那么我们可以考虑将状态中的某一维放进 \(dp\) 值里。
首先尝试把 \(q\) 换进去,状态设计为 \(dp_{i,j}\) 为剩余区间 \([i,j]\) 时进行的最大操作数为 \(q\)。
那么我们怎么转移?从大往小枚举区间,然后根据当前进行的操作,每次查询满足要求的前缀后缀,转移一下即可。
此时我们不难发现,\(q\) 的最大值只能是 \(n\),根本无法取到更大。这就是这题的诈骗点。
时间复杂度是 \(O(n^3)\) 的,而我们可以发现无法继续优化下去(四边形不等式等都用不了),就要换一种思路。
贪心
显然,对于一段区间而言,长度越长,自然是对答案更优。为什么?因为每次操作都可以留出更多的空间来操作。
于是我们考虑固定左端点,把右端点换出来。
正解
设计状态 \(dp_{q,i}\) 表示进行到了第 \(q\) 次操作,左端点为 \(i\) 时的最大右端点在哪。
每次操作可以选前缀、后缀,于是我们分两种转移。
前缀
\(dp_{q,i}\) 能转移当且仅当 \([i-d,i-1]\) 能被消掉,然后转移左端点在 \(i\) 前面的 \(j\) 的所有 \(dp_{q-1,j}\) 的值。
这个可以做一个很显然的前缀和优化,不再细说。
后缀
感觉这个比较难搞。
\(dp_{q,i}\) 能转移的条件是在 \([j,dp_{q-1,j}]\) 中有能消除的后缀,同时在这些后缀中取最大的左端点转移。
观察到 \(dp_{q-1,j}\) 也在 \([1,n]\) 之间,于是我们可以预处理出对于每一个点,在他左边的最大可消除后缀的左端点在哪,这个可以 \(O(n)\) 处理出。
然后每次转移一下即可。
总体时间复杂度 \(O(\min(n,q)n)\)。
细节
特判整个序列被删完的情况。只需要在删后缀里面加特判即可。因为要删完肯定是一次删全部,那么此时就没有前缀后缀之分了,算哪个都可以。
代码
#include <bits/stdc++.h>
#define fi first
#define se second
#define lc (p<<1)
#define rc ((p<<1)|1)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pi;
int n,q,a[5005],mn[5005][5005],dp[5005][5005],rmx[5005];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>q;
for(int i=1;i<=n;i++)cin>>a[i];
memset(mn,0x3f,sizeof(mn));
for(int i=1;i<=n;i++)
{
mn[i][i]=a[i];
for(int j=i+1;j<=n;j++)mn[i][j]=min(mn[i][j-1],a[j]);
}
memset(dp,-1,sizeof(dp));
dp[0][1]=n;
for(int i=1;i<=min(n,q);i++)
{
bool ed=1;
int d,s,pre=-1,p=-1;
cin>>d>>s;
for(int j=1;j<=n;j++)
{
if(j-d>=1)pre=max(pre,dp[i-1][j-d]);
if(j-d>=1&&mn[j-d][j-1]>=s)dp[i][j]=max(dp[i][j],pre);
}
for(int j=1;j<=n;j++)
{
if(j-d+1>=1&&mn[j-d+1][j]>=s)p=max(p,j-d+1);
rmx[j]=p;
}
for(int j=1;j<=n;j++)
{
if(rmx[dp[i-1][j]]-1>=j)dp[i][j]=max(dp[i][j],rmx[dp[i-1][j]]-1);
if(dp[i][j]<j)dp[i][j]=-1;
if(rmx[dp[i-1][j]]==j)ed=0;
}
for(int j=1;j<=n;j++)if(dp[i][j]!=-1)ed=0;
if(ed)
{
cout<<i-1;
return 0;
}
}
cout<<q;
return 0;
}
Luogu P9180 [COCI2022-2023#5] Slastičarnica 题解 [ 蓝 ] [ 区间 dp ] [ dp 状态优化 ] [ 前缀和优化 ]的更多相关文章
- luogu P1549 棋盘问题(2) 题解
luogu P1549 棋盘问题(2) 题解 题目描述 在\(N * N\)的棋盘上\((1≤N≤10)\),填入\(1,2,-,N^2\)共\(N^2\)个数,使得任意两个相邻的数之和为素数. 例如 ...
- 【luogu P1314 聪明的质监员】 题解
题目链接:https://www.luogu.org/problemnew/show/P1314 二分答案 但是计算区间贡献的时候 直接暴力会挂 前缀和加速 #include <cstdio&g ...
- BZOJ 2023 [Usaco2005 Nov]Ant Counting 数蚂蚁:dp【前缀和优化】
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2023 题意: 有n个家族,共m只蚂蚁(n <= 1000, m <= 1000 ...
- 题解——洛谷P2734 游戏A Game 题解(区间DP)
题面 题目背景 有如下一个双人游戏:N(2 <= N <= 100)个正整数的序列放在一个游戏平台上,游戏由玩家1开始,两人轮流从序列的任意一端取一个数,取数后该数字被去掉并累加到本玩家的 ...
- 【题解】POJ1934 Trip (DP+记录方案)
[题解]POJ1934 Trip (DP+记录方案) 题意: 传送门 刚开始我是这么设状态的(谁叫我DP没学好) \(dp(i,j)\)表示钦定选择\(i\)和\(j\)的LCS,然而你会发现这样钦定 ...
- 【题解】剪纸条(dp)
[题解]剪纸条(dp) HRBUST - 1828 网上搜不到题解?那我就来写一篇吧哈哈哈 最优化问题先考虑\(dp\),设\(dp(i)\)表示将前\(i\)个字符(包括\(i\))分割成不相交的回 ...
- 【题解】ARC101F Robots and Exits(DP转格路+树状数组优化DP)
[题解]ARC101F Robots and Exits(DP转格路+树状数组优化DP) 先删去所有只能进入一个洞的机器人,这对答案没有贡献 考虑一个机器人只能进入两个洞,且真正的限制条件是操作的前缀 ...
- 【题解】地精部落(DP)
[题解]地精部落(DP) 设\(f_i\)表示强制第一个是谷的合法方案数 转移枚举一个排列的最大值在哪里,就把序列分成了互不相干的两个部分,把其中\(i-1\choose j-1\)的数字分配给前面部 ...
- 【luogu P2279 [HNOI2003]消防局的设立】 题解
题目链接:https://www.luogu.org/problemnew/show/P2279 想怎么贪怎么贪 #include <queue> #include <cstdio& ...
- 【luogu P2762 太空飞行计划问题】 题解
题目链接:https://www.luogu.org/problemnew/show/P2762 算是拍照那个题的加强下. 输入真的很毒瘤.(都这么说但好像我的过了?) #include <qu ...
随机推荐
- Django Admin之常用功能汇总
1.字段支持下拉搜索框 1)在admin中新增字段autocomplete_fields autocomplete_fields = ("field1","field2& ...
- PHP编译安装之常见问题
正式服的PHP环境,一般都会进行编译安装,汇总一下经常遇到的一些问题 1.Call to undefined function crmeb\utils\imagecreate 解决:需要安装gd库 1 ...
- Fiddler模拟网络超时
前情 最近在优化接口请求错误的报错提示,希望尽可能的能从提示语知道当前错误大致原因,于是我需要模拟各种错误请求的状况. 问题 网络超时是很常见的接口请求错误情况,在没有服务端配合的情况下,我需要怎样来 ...
- QPixmap 线程 奔溃
使用QImage替代QPixmap. ·QImage与Qpixmap的区别 1.QPixmap主要是用于绘图,针对屏幕显示而最佳化设计,QImage主要是为图像I/O.图片访问和像素修改而设计的 2. ...
- docker-compose的nginx更换完ssl证书不起作用的完美解决方法
以Harbor为例,ssl证书更新后,docker-compose启动不起作用. 问题出在一句很重要的命令:./prepare 步骤:(Harbor样例) 1. cd /data/ssl 换ssl证 ...
- 【C#】【平时作业】习题-6-静态成员
习题-6静态成员 一.概念题 1. 什么是静态成员 被static修饰的成员,叫做静态成员.静态成员是属于类的.通过类名直接访问. 当类第一次被访问的时候,就会将这个类下面的所有的静态成员创建在内存当 ...
- arch 输入法
输入法配置 输入法采用fcitx + Sogou的组合,安装需要的包: yay -S fcitx fcitx-im fcitx-configtool fcitx-sogoupinyin 然后写一个fc ...
- Qt开源作品32-文本框回车焦点下移
一.前言 这个demo由于太过简单,而不用过多的文字描述,其实就是实现了在一个文本框中输入完成以后,回车自动跳入下一个文本框,焦点下移,这个在很多的社保系统.医疗系统等系统中很常用,因为那些系统需要很 ...
- 这是我见过最通俗易懂的SVD(奇异值分解)算法介绍
线性代数是机器学习领域的基础,其中一个最重要的概念是奇异值分解(SVD),本文尽可能简洁的介绍SVD(奇异值分解)算法的基础理解,以及它在现实世界中的应用. SVD是最广泛使用的无监督学习算法之一,它 ...
- C#中如何将图片添加为程序的资源
C#中将图片添加为程序的资源的步骤: 1.在C#程序的"Properties"文件夹中双击Resources.resx文件,以便打开资源文件,使其处于可编辑状态: 2.在打开后的R ...