洛谷题单指南-前缀和差分与离散化-P4375 [USACO18OPEN] Out of Sorts G
原题链接:https://www.luogu.com.cn/problem/P4375
题意解读:计算双向冒泡排序一共要进行多少趟。
解题思路:一道思维难度较大的题!
由于数据各不相同,先将其离散化处理从1~n的数,如果每个数不在自己的位置则是无序。
对于双向冒泡排序,对于第x个位置来说,每一趟正向一定会有一个大于x的数交换到x的后,每一趟反向会有一个小于x的数交换到x前面
因此一共要进行多少趟上述过程?取决于对于每一个位置x,从1~x有多少个数大于x,取最大的个数即可。
这里的关键在于如何统计每个位置前有多少个数大于x!
一种O(n)方法:
设cnt表示截止当前位置有多少个数大于当前位置编号
枚举1~n的位置x
对于每一个位置的数num[x],如果num[x]>x,则cnt++
如果x在前面位置作为数值访问过,则当时肯定导致了cnt++,此时必须cnt--,因为此时位置变成x,前面的数值x不能大于x了
标记num[x]已访问过
更新答案ans = max(ans, cnt)
注意:如果已经排好序,至少要进行一趟,ans初始值为1。
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n;
bool vis[N];
struct node
{
int val, id;
} a[N];
bool cmp1(node a, node b)
{
return a.val < b.val;
}
bool cmp2(node a, node b)
{
return a.id < b.id;
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i].val, a[i].id = i;
sort(a + 1, a + n + 1, cmp1);
for(int i = 1; i <= n; i++) a[i].val = i; //离散化
sort(a + 1, a + n + 1, cmp2); //恢复原顺序
int ans = 1;
int cnt = 0; //当前位置i~1有多个数大于i
for(int i = 1; i <= n; i++)
{
if(a[i].val > i) cnt++;
if(vis[i]) cnt--; //i在前面数字出现过,说明当时肯定导致cnt++,到第i个的时候之前出现的数字i效果就不再,就要cnt--
vis[a[i].val] = true;
ans = max(ans, cnt);
}
cout << ans;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?