追寻


题目链接:P4933 大师
把“等差子序列”按 最后一项 和 公差 分类。
逐个枚举位置 \(i\) 作为最后一项,用哈希表维护:
“以 \(a_i\) 结尾、某个公差 \(d\) 的等差子序列有多少个”。
设输入数组为 \(a[0..n-1]\) , 约定 \(a[i]\) 为 \(a_i\) 。
定义状态:
\(dp[i][d]\) 表示:以 \(a_i\) 结尾、公差为 \(d\) 的等差子序列个数(长度 ≥ 2)。
固定 \(i\),枚举所有 \(j < i\),令 \(d = a_i - a_j\)
此时会产生两类贡献:
新长度为 2 的等差子序列:\((a_j, a_i)\)
贡献 \(+1\)
把所有以 \(a_j\)
结尾、公差同为 \(d\) 的等差子序列接上
\(a_i\)
贡献 \(+dp[j][d]\)
因此:
\(dp[i][d] += dp[j][d] + 1\)
完整状态转移方程如下:
\[ dp[i][a_i-a_j] = dp[i][a_i-a_j] + dp[j][a_i-a_j] + 1 \]
\[ cnt \;\; +\!\!= \sum_{j>=0}^{i-1} dp[j][a_i-a_j] + 1 \]
同时,题目要求统计所有等差子序列总数。
每次转移新增了 \(dp[j][d] + 1\)
个合法子序列,所以直接累加到答案即可。
外层 \(i\),内层 \(j\):时间复杂度 \(O(n^2)\)
使用 哈希表(unordered_map) 按需存储不同公差,减少内存使用。
下面代码按照上述 DP 直接实现:
\(dp[i]\) 是一个哈希表:key 为公差,value 为方案数。
每次枚举 \((j, i)\) 更新 \(dp[i][d]\),并把新增数量累加到 \(cnt\)。
1 | #include <bits/stdc++.h> |
学期结束了。
舍友下午六点离开,我去送他。
风很冷。我穿得单薄,身体发凉。路上我尽力找话说,让空气不要太快冷下来。
“再见。”
“再见。”
他走了。
我去食堂吃饭,麻油拌面。不好吃。
想了想,又去买了瓶饮料。结账的时候,店员送了一包鱼干。
出门时,正好遇见高中同学——这是在这所大学里唯一的一个。
说话的声音不自觉地高了一点。寒暄,告别。
风又吹过来。
我回到寝室。