日常刷题2025-2-14

日常刷题2025-2-14

小鸡的排列构造的checker

https://ac.nowcoder.com/acm/contest/95338/I

题目大意

给你一个排列,给你一系列操作 li ri ci,将 li ri 范围的数字排序,原来位置 ci 处的数字移动到了哪里。

思路:树状数组+离线

本题预期的做法是使用离线将查询排序的技巧,使用树状数组进行维护。

我们举一个例子说明该做法的思路,例如输入的数组 ppp 为 [1,3,2,4,5],查询分别为 [1,5,2] 和 [2,5,4],我们发现 [1,5,2]查询相当于在问: [1,5]区间里有多少个小于等于 p2 的数字?(因为这些数的个数能得出排序后 p2 的位置)。

于是我们可以维护一个初始全 0 的树状数组,按照 pi 从小到大给树状数组的对应位置 +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(nlog⁡n)。

代码

#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;
}

好伙计猜拳

https://ac.nowcoder.com/acm/contest/95338/B

思路:最长上升子序列

https://www.bilibili.com/video/BV1yhKVeDEJE/?spm_id_from=333.337.search-card.all.click&vd_source=4a339d299e165d8fe38b9926c5240eae

评述

有两种操作,每种操作的代价不同,很容易让人以为是贪心,但是思考贪心要考虑的因素有非常多,此时可以想一想是不是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 中国大陆许可协议进行许可。

posted @   califeee  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.