日常刷题2025-2-14
1.日常刷题2023-3-112.日常训练2025-1-23.日常训练2025-1-34.日常训练2025-1-55.日常训练2025-1-86.日常训练2025-1-117.日常训练2025-1-128.日常训练2025-1-139.日常训练2025-1-1410.日常训练2025-1-1511.日常训练2025-1-1612.日常训练2025-1-1713.日常训练2025-1-1814.日常训练2025-1-1915.日常训练2025-1-2116.日常训练2025-1-2217.日常刷题2025-1-2318.日常训练2025-1-2419.日常刷题2025-1-2520.日常刷题21.日常刷题2025-2-622.日常刷题2025-2-9
23.日常刷题2025-2-14
24.日常刷题2025-2-1525.日常刷题2025-2-1726.日常刷题2025-2-2027.日常刷题2025-2-2128.日常刷题2025-2-2229.日常刷题2025-2-2430.日常刷题2025-2-2631.日常刷题2025-2-2732.日常刷题2025-2-2833.日常刷题2025-3-134.日常刷题2025-3-235.日常刷题2025-3-336.日常刷题2025-3-537.日常刷题2025-3-638.日常刷题2025-3-739.日常刷题2025-3-840.日常刷题2025-3-941.日常刷题2025-3-10日常刷题2025-2-14
小鸡的排列构造的checker
题目大意
给你一个排列,给你一系列操作
,将 范围的数字排序,原来位置 处的数字移动到了哪里。
思路:树状数组+离线
本题预期的做法是使用离线将查询排序的技巧,使用树状数组进行维护。
我们举一个例子说明该做法的思路,例如输入的数组 ppp 为 [1,3,2,4,5],查询分别为 [1,5,2] 和 [2,5,4],我们发现 [1,5,2]查询相当于在问: [1,5]区间里有多少个小于等于
的数字?(因为这些数的个数能得出排序后 的位置)。 于是我们可以维护一个初始全 0 的树状数组,按照
从小到大给树状数组的对应位置 +1,也就是在上述例子中,树状数组维护的原数组依次是: 状态1:[1,0,0,0,0] 状态2:[1,0,1,0,0] 状态3:[1,1,1,0,0] 状态4:[1,1,1,1,0] 状态5:[1,1,1,1,1]
这样询问 [1,5,2] 其实是在对状态2的数组求 [1,5] 区间的和,使用树状数组可以做到;询问 [2,5,4] 其实是在对状态4的数组求 [2,5] 区间的和,使用树状数组可以做到。
因此,像上述过程一样,把所有 [l,r,c] 询问按照 p[c] 从小到大排序,树状数组维护上述过程即可,复杂度 O(nlogn)。
代码
#include <bits/stdc++.h> using u64 = unsigned long long; using i64 = long long; typedef std::pair<int, int> pii; const int INF = 0x3f3f3f3f; const int mod = 998244353; const long long LINF = 1e18; void solve(){ int n, m; std::cin >> n >> m; std::vector<int> p(n+1), pos(n+1); for (int i = 1; i <= n; i++){ std::cin >> p[i]; pos[p[i]] = i; } std::vector q(n+1, std::vector<int>()); std::vector<int> l(m), r(m), c(m); for (int i = 0; i < m; i++){ std::cin >> l[i] >> r[i] >> c[i]; q[p[c[i]]].push_back(i); } std::vector<int> bit(n+1); auto add = [&](int i)->void{ for ( ; i <= n; i += i & -i) bit[i] += 1; }; auto sum = [&](int i)->int{ int res = 0; for ( ; i; i -= i & -i){ res += bit[i]; } return res; }; std::vector<int> ans(m); for (int i = 1; i <= n; i++){ for (auto j : q[i]) ans[j] = sum(r[j]) - sum(l[j]-1) + l[j]; add(pos[i]); } for (auto e : ans) std::cout << e << '\n'; } signed main(){ std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(15); int t = 1, i; std::cin >> t; for (i = 0; i < t; i++){ solve(); } return 0; }
好伙计猜拳
思路:最长上升子序列
评述
有两种操作,每种操作的代价不同,很容易让人以为是贪心,但是思考贪心要考虑的因素有非常多,此时可以想一想是不是DP,发现题目是无后效性的,所以可以DP。
无后效性:已经求解的子问题,不会再受到后续决策的影响。
代码
#include <bits/stdc++.h> using u64 = unsigned long long; using i64 = long long; typedef std::pair<int, int> pii; const int INF = 0x3f3f3f3f; const int mod = 998244353; const long long LINF = 1e18; void solve(){ i64 n, c1, c2; std::cin >> n >> c1 >> c2; std::vector<i64> a(n+1), b(n+1); std::vector<std::vector<i64>> dp(n+1, std::vector<i64>(2, 1e18)); for (int i = 1; i <= n; i++) std::cin >> a[i] >> b[i]; dp[0][0] = 0; i64 ans = 1e18; for (int i = 1; i <= n; i++){ for (int j = 0; j <= i - 1; j++){ if (a[j] <= a[i] && b[j] <= b[i]){ dp[i][0] = std::min(dp[i][0], dp[j][0] + c1*(i-j-1)); } if (b[j] <= a[i] && a[j] <= b[i]){ dp[i][0] = std::min(dp[i][0], dp[j][1] + c1*(i-j-1)); } } for (int j = 0; j <= i - 1; j++){ if (a[j] <= b[i] && b[j] <= a[i]){ dp[i][1] = std::min(dp[i][1], dp[j][0] + c1*(i-j-1)); } if (b[j] <= b[i] && a[j] <= a[i]){ dp[i][1] = std::min(dp[i][1], dp[j][1] + c1*(i-j-1)); } } dp[i][1] += c2; ans = std::min(ans, std::min(dp[i][0], dp[i][1])+c1*(n-i)); } std::cout << ans << '\n'; } signed main(){ std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(15); int t = 1, i; std::cin >> t; for (i = 0; i < t; i++){ solve(); } return 0; }
本文作者:califeee
本文链接:https://www.cnblogs.com/califeee/p/18715430
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现