Hetao P1031 萌萌题 题解 [ 蓝 ] [ 线性 dp ]
萌萌题:一道结合了观察性质的线性 dp。
观察
我们先考虑极端情况:所有数相同,所有数降序排列两种情况。
对于所有数相同的情况,我们发现,最终可以合并出来的区间,最多只有
怎么证明?考虑固定右端点,那么我们想要合并出一个点,就得选
所有数降序排列是多少?我们只需要将最后两个元素合并,然后继续往前面合并即可。总体来说有
dp 设计
这题还有个很重要的观察:对于固定了右端点的时候,假设我们要让这个数增加
为什么要前一个数?其实你不要这前一个数其实也可以做。只不过我这样设计来讲比较好写转移的代码。
接下来就是很显然的转移,假设目前合并到的区间的左端点的前一个数为
然后记录一下合法状态就好了。
这样写对吗?实际上假了。这是我赛时的做法,当时误以为一个数最多增量只可能是
那么开大小为
注意,当某个区间无法继续合并下去的时候,要立刻 break,才能保证复杂度正确,否则会退化为平方级别。
时间复杂度为
代码
#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,a[100005],ans=0;
vector<int>dp[100005];
int main()
{
freopen("cute.in","r",stdin);
freopen("cute.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)
{
dp[i].emplace_back(i-1);
for(int j=1;j<=100000;j++)
{
int now=dp[i][j-1];
int ta=a[now];
int dt=a[i]+j-1-ta;
if(dt>=0&&dt<dp[now].size())dp[i].emplace_back(dp[now][dt]);
else break;
}
}
for(int i=1;i<=n;i++)ans=max(ans,a[i]+int(dp[i].size())-1);
cout<<ans<<endl;
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战