【JZOJ6288】【NOIP提高组A】旋转子段
题目大意
给出一个n的排列,若a[i]=i则i是一个固定点,现在你可以选一个区间翻转它,求翻转过后固定点的最大值(只能选一个区间,翻转一次)。
分析
对于一次交换(i,j)只会有三种情况:
- i不在自己的位置上,交换后复位了。(j同理)
- i不在自己的位置上,交换后仍不在。
- i原来在自己的位置上,交换后不在了。
后两种用前缀和统计就行了,第一种的话,我们求出(i,a[i])的中心,把(i,a[i])挂在中心上,然后按长度排序,我们只用处理有元素复位的交换,其它交换用前缀和就能统计了。
Code
代码有点丑,见谅。
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100007;
int n, ret = -0x3f3f3f3f, sum[N], a[N];
struct note { int l, r, len; };
vector<note> lis1[N], lis2[N];
int cmp(note a, note b) { return a.len < b.len; }
void doit1()
{
for (int i = 1, p, q; i <= n; i++)
{
p = i, q = a[i];
if (p > q) swap(p, q);
if ((q - p) % 2 == 0) lis1[(p + q) / 2].push_back((note){p, q, q - p + 1});
}
for (int i = 1; i <= n; i++)
{
sort(lis1[i].begin(), lis1[i].end(), cmp);
int sz = lis1[i].size(), s = 0;
for (int j = 0, lasl = i, lasr = i; j < sz; j++)
{
if (lis1[i][j].len == 1) { ret = max(ret, s); continue; }
if (lis1[i][j].l < lasl) s -= sum[lasl - 1] - sum[lis1[i][j].l];
if (lasr < lis1[i][j].r) s -= sum[lis1[i][j].r - 1] - sum[lasr];
if (j < sz - 1)
{
if (lis1[i][j].len == lis1[i][j + 1].len) s += 2, ++j;
else s += 1;
}
else s += 1;
lasl = lis1[i][j].l, lasr = lis1[i][j].r;
ret = max(ret, s);
}
}
}
void doit2()
{
for (int i = 1, p, q; i <= n; i++)
{
p = i, q = a[i];
if (p > q) swap(p, q);
if ((q - p) % 2 == 1) lis2[(p + q) / 2].push_back((note){p, q, q - p + 1});
}
for (int i = 1; i <= n; i++)
{
sort(lis2[i].begin(), lis2[i].end(), cmp);
int sz = lis2[i].size(), s = 0;
for (int j = 0, lasl = i + 1, lasr = i; j < sz; j++)
{
if (lis2[i][j].l < lasl) s -= sum[lasl - 1] - sum[lis2[i][j].l];
if (lasr < lis2[i][j].r) s -= sum[lis2[i][j].r - 1] - sum[lasr];
if (j < sz - 1)
{
if (lis2[i][j].len == lis2[i][j + 1].len) s += 2, ++j;
else s += 1;
}
else s += 1;
lasl = lis2[i][j].l, lasr = lis2[i][j].r;
ret = max(ret, s);
}
}
}
int main()
{
//freopen("rotate.in", "r", stdin);
//freopen("rotate.out", "w", stdout);
//freopen("in", "r", stdin);
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]), sum[i] = sum[i - 1] + (i == a[i]);
doit1();
doit2();
printf("%d\n", sum[n] + ret);
return 0;
}
作者:zjlcnblogs
出处:https://www.cnblogs.com/zjlcnblogs/p/11328305.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
分类:
OI
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
· 对象命名为何需要避免'-er'和'-or'后缀
· “你见过凌晨四点的洛杉矶吗?”--《我们为什么要睡觉》
· 编程神器Trae:当我用上后,才知道自己的创造力被低估了多少
· 开发的设计和重构,为开发效率服务
· 从零开始开发一个 MCP Server!
· Ai满嘴顺口溜,想考研?浪费我几个小时