Compare commits

...

2 Commits

Author SHA1 Message Date
de497e2c80 docs: 更新README添加P6476题解易错点
添加P6476题解中的四个关键易错点说明,包括循环顺序、清空操作优化、下标偏移处理以及状态转移公式注意事项
2025-10-11 12:13:40 +08:00
b2c80a8161 feat: 添加P6006.cpp实现三元组计数算法
实现一个动态规划算法来计算满足条件的三元组数量,用于解决特定范围的查询问题。算法通过预处理和动态规划表优化查询效率,并处理了数组边界条件和内存使用问题。
2025-10-11 12:10:13 +08:00
2 changed files with 65 additions and 0 deletions

View File

@ -1,4 +1,11 @@
# 算法笔记
## P6476 题解易错点
1. **循环顺序**dp注意必须从遍历顺序i从n-2递减正向遍历会导致状态转移错误
2. **清空操作优化**每次使用后需要清空tot数组但直接memset会超时改用标记数组记录修改位置
3. **下标偏移**结构体T使用of常量处理负数下标数组大小需要*2
4. **状态转移公式**注意容斥原理的应用dp[i][j] = 当前三元组数 + 子区间累计值 - 重复部分
## 线性动态规划优化为$O(n\log{n})$方法
>如果是递增序列就lower_bound

58
src/10/10/P6006.cpp Normal file
View File

@ -0,0 +1,58 @@
#include <cstdint>
#include <iostream>
#include <istream>
#include <vector>
using ll = int64_t;
const ll maxn = 5e3+5;
ll n,q, dp[maxn][maxn], a[maxn];
struct T{
const static ll of = 2e6+3;
ll v[4*ll(1e6+5)]; // 注意限制的大小要*2
inline ll&operator[](const ll n){
return v[n+of];
}
}tot;
std::vector<ll> used;
int main(){
std::iostream::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cin>>n>>q;
for(ll i=1;i<=n;i++){
std::cin>>a[i];
}
for(ll i=n-2;i>=1;i--){ // 注意循环顺序!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
for(ll j:used)tot[j]=0; // 注意清空耗时
used.clear();
tot[a[i+1]]++;
used.emplace_back(a[i+1]);
for(ll j=i+2;j<=n;j++){
dp[i][j] = tot[-(a[i]+a[j])];
// printf("before dp[%lld][%lld]=%lld\n",i,j,dp[i][j]);
dp[i][j] += dp[i+1][j] + dp[i][j-1] - dp[i+1][j-1];
tot[a[j]]++;
used.emplace_back(a[j]);
// printf("after dp[%lld][%lld]=%lld\n",i,j,dp[i][j]);
}
}
while(q--){
ll a,b;
std::cin>>a>>b;
std::cout<<dp[a][b]<<"\n";
}
}
/*
dp[i][j] = i~j的
dp[i][j] = dp[i+1][j] + dp[i][j-1] - dp[i+1][j-1]
*/