Luogu P4933 大师 题解 [ 绿 ] [ 线性 dp ] [ dp 细节处理 ] [ 限制转移条件优化 ]
依据值域的 \(O(n^2)\) 做法
这种做法只适用于这种值域小的题,下一种做法才是求等差数列的通解。
我们定义 \(f[i][j]\) 表示以 \(h_i\) 为最后一个数,公差为 \(j\) 的等差数列(长度 \(\ge 2\) ) 的个数。
接下来我们找每一个数前面的数,确定公差后转移即可。时间 \(O(n^2)\) 。
细节
表面上这道题很简单,但实际上细节非常多,一不小心就会挂,更何况这题的样例还比较大,不好调试。
首先,我们要把长度为 \(1\) 的等差数列个数记录到 \(ans\) 中(不加到 dp 数组里),即 \(n\) ,因为我们后面不会在考虑这些特殊的等差数列。
其次,我们在转移到时候,看似会这样写:
\]
(省略本题原本要加的负数偏移量和取模操作)
其实并不对,因为我们转移的是它前面长度大于 \(1\) 的等差数列,在当时这些长度为 \(1\) 的不用算,但一旦转移到我们这里,这些长度为 \(1\) 的序列长度就变成 \(2\) 了,因此是要计算的。
考虑到每次转移,原先长度为 \(1\) 的只有一个,我们只要在转移的时候 \(+1\) 即可。
\]
还有一个细节,就是在统计答案的时候,能否是:
\]
实际上不行,因为每次遍历 \(j\) 如果都加一遍 \(f[i][j]\) ,那么如果在 \(i\) 前面有两个数一样,就会导致公差相同,这时候加 \(f[i][j]\) ,就会导致先更新的那种情况被加了两次,导致答案偏大。
解决办法就是把 \(ans\) 和 dp 数组一起转移:
\]
\]
于是就好了。
注意要取模,由于公差可能是负数,所以还要加一个偏移量。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353,eps=40005;
int n,h[1005];
ll ans=0,f[1005][100005];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
ans=(ans+1)%mod;
cin>>h[i];
for(int j=1;j<i;j++)
{
f[i][h[i]-h[j]+eps]=(f[i][h[i]-h[j]+eps]+f[j][h[i]-h[j]+eps]+1)%mod;
ans=(ans+f[j][h[i]-h[j]+eps]+1)%mod;
}
}
cout<<ans%mod;
return 0;
}
如果你不想考虑这么多,那么在全部转移完后再遍历一遍 dp 数组求方案也是可以的,这样就可以让 \(ans\) 直接加 \(f[i][j]\) 了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353,eps=40005;
int n,h[1005];
ll ans=0,f[1005][100005];
int main()
{
cin>>n;
ans=n;
for(int i=1;i<=n;i++)
{
cin>>h[i];
for(int j=1;j<i;j++)
{
f[i][h[i]-h[j]+eps]=(f[i][h[i]-h[j]+eps]+f[j][h[i]-h[j]+eps]+1)%mod;
}
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<=100000;j++)
{
ans+=f[i][j];
ans%=mod;
}
}
cout<<ans%mod;
return 0;
}
基于数的多少的 \(O(n^2)\)~\(O(n^3)\) 的做法
定义 \(f[i][j]\) 表示前一项为 \(h_i\) ,最后一项为 \(h_j\) 的等差数列的个数。
转移的细节和上面基本一样,就不说明了。
很自然的转移方程:
\]
时间 \(O(n^3)\) ,常数为 \(\frac{1}{6}\) ,稳过 \(10^3\) 数据。
优化就是把每个数的下标存进 unordered_map<int,vector<int>> 里,转移的时候避免多转移即可。
理想状态为 \(O(n^2)\) ,要是被卡哈希或者构造所有数相同的数据可能会到 \(O(n^3)\) 甚至带更大的常数。但概率比较小。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
int n,h[1005];
ll f[1005][1005],ans=0;
unordered_map<int,vector<int> >m;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>h[i];
m[h[i]].push_back(i);
}
ans=n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<i;j++)
{
f[j][i]=1;
vector<int>v=m[h[j]-(h[i]-h[j])];
for(int k=0;k<v.size()&&v[k]<j;k++)
{
int frm=v[k];
f[j][i]+=f[frm][j];
f[j][i]%=mod;
}
ans+=f[j][i];
ans%=mod;
}
}
cout<<ans%mod;
return 0;
}
Luogu P4933 大师 题解 [ 绿 ] [ 线性 dp ] [ dp 细节处理 ] [ 限制转移条件优化 ]的更多相关文章
- Luogu P4933 大师(dp)
P4933 大师 题意 题目背景 建筑大师最近在跟着数学大师ljt12138学数学,今天他学了等差数列,ljt12138决定给他留一道练习题. 题目描述 ljt12138首先建了\(n\)个特斯拉电磁 ...
- Luogu P4933 大师【dp】By cellur925
题目传送门 题目大意:给你一个序列,求子序列为等差数列的子序列个数.序列长度$n<=2000$,最高的塔高$v<=20000$. 这种计数类的题,大概就是dp的套路了⑧.开始设计的是一个错 ...
- E - Max Sum Plus Plus Plus HDU - 1244 (线性区间DP)
题目大意: 值得注意的一点是题目要求的是这些子段之间的最大整数和.注意和Max Sum Plus Plus这个题目的区别. 题解: 线性区间DP,对每一段考虑取或者不取.定义状态dp[i][j]指的 ...
- Luogu P1541 乌龟棋 【线性dp】
题目背景 小明过生日的时候,爸爸送给他一副乌龟棋当作礼物. 题目描述 乌龟棋的棋盘是一行 N 个格子,每个格子上一个分数(非负整数).棋盘第1格是唯一的起点,第 N 格是终点,游戏要求玩家控制一个乌龟 ...
- 【题解】POJ1934 Trip (DP+记录方案)
[题解]POJ1934 Trip (DP+记录方案) 题意: 传送门 刚开始我是这么设状态的(谁叫我DP没学好) \(dp(i,j)\)表示钦定选择\(i\)和\(j\)的LCS,然而你会发现这样钦定 ...
- 【题解】剪纸条(dp)
[题解]剪纸条(dp) HRBUST - 1828 网上搜不到题解?那我就来写一篇吧哈哈哈 最优化问题先考虑\(dp\),设\(dp(i)\)表示将前\(i\)个字符(包括\(i\))分割成不相交的回 ...
- 【题解】地精部落(DP)
[题解]地精部落(DP) 设\(f_i\)表示强制第一个是谷的合法方案数 转移枚举一个排列的最大值在哪里,就把序列分成了互不相干的两个部分,把其中\(i-1\choose j-1\)的数字分配给前面部 ...
- (线性结构dp )POJ 1260 Pearls
Pearls Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 10558 Accepted: 5489 Descripti ...
- 【Luogu】P3239亚瑟王(概率DP)
题目链接 请看luogu第一篇题解 #include<cstdio> #include<algorithm> #include<cstring> #include& ...
- LibreOJ 6177 题解(状压DP)
题面 传送门 分析 刚看到这道题时想的是跟最短哈密顿路类似的二进制状压DP,先用floyd处理距离 但是此题用二进制不够,应该用三进制 0,1,2分别表示未送,正在送,已送完 dp[s][i]表示当前 ...
随机推荐
- JPEG格式研究——(4)反量化、逆ZigZag变化和IDCT变换
反量化 反量化其实很简单,将霍夫曼解码出来的数据乘上对应的量化表就好了 通过当前色度选择出SOF中的Component,其中的Tqi指出了这一色度所需的量化表id Component的结构如下: 名称 ...
- 超详细 HarmonyOS 开发教程之开发环境搭建指南
HarmonyOS开发环境搭建指南:DevEco Studio安装教程 一.系统要求 操作系统:Windows 10 64位或更高版本 RAM:至少8GB,推荐16GB 硬盘空间:至少10GB可用空间 ...
- uni-app Vue3项目引入Tailwind CSS
前情 Tailwind CSS 是一个原子类 CSS 框架,它将基础的 CSS 全部拆分为原子级别,同时还补全各种浏览器模式前缀,兼容性也不错.它的工作原理是扫描所有 HTML 文件.JavaScri ...
- 2024-12-18:正方形中的最多点数。用go语言,给定一个二维数组 points 和一个字符串 s,其中 points[i] 表示第 i 个点的坐标,s[i] 表示第 i 个点的标签。 如果一个正
2024-12-18:正方形中的最多点数.用go语言,给定一个二维数组 points 和一个字符串 s,其中 points[i] 表示第 i 个点的坐标,s[i] 表示第 i 个点的标签. 如果一个正 ...
- 08C++选择结构(2)——教学
一.逻辑变量 教学视频 存储类似灯亮或灯灭.是男还是女等结果只有两种可能的数据时,可以使用逻辑型变量. 逻辑型变量用关键字bool定义,所以又称为布尔变量,其值只有两个false(假)和true(真) ...
- 中电金信多模态鉴伪技术抵御AI造假威胁
AI换脸技术,属于深度伪造最常见方式之一,是一种利用人工智能生成逼真的虚假人脸图片或视频的技术.基于深度学习算法,可以将一个人的面部特征映射到另一个人的面部,创造出看似真实的伪造内容.近年来,以A ...
- 强化学习算法中的log_det_jacobian
相关: https://colab.research.google.com/github/google/brax/blob/main/notebooks/training_torch.ipynb 之前 ...
- spring boot 启动原理解析
https://www.cnblogs.com/xiaoxi/p/7999885.html 我们开发任何一个Spring Boot项目,都会用到如下的启动类 1 @SpringBootApplicat ...
- 国产系统中标麒麟neokylin上的视频监控系统
一.功能特点 (一)软件模块 视频监控模块,各种停靠小窗体子模块,包括设备列表.图文警情.窗口信息.云台控制.预置位.巡航设置.设备控制.悬浮地图.网页浏览等. 视频回放模块,包括本地回放.远程回放. ...
- CentOS 集群初始化设置
0. 前置操作 centos-7.9.2009-isos-x86_64安装包下载_开源镜像站-阿里云 下载CentOS-7-x86_64-DVD-2009.iso即可 1. 配置静态网络 1.1 查看 ...