Processing math: 10%

【JZOJ6288】【NOIP提高组A】旋转子段

题目大意

给出一个n的排列,若a[i]=ii是一个固定点,现在你可以选一个区间翻转它,求翻转过后固定点的最大值(只能选一个区间,翻转一次)。

分析

对于一次交换(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 国际」许可协议进行许可。

posted @ 2019-08-09 16:56  gz-gary  阅读(138)  评论(0)    收藏  举报
编辑推荐:
· 复杂业务系统线上问题排查过程
· 通过抓包,深入揭秘MCP协议底层通信
· 记一次.NET MAUI项目中绑定Android库实现硬件控制的开发经历
· 糊涂啊!这个需求居然没想到用时间轮来解决
· 浅谈为什么我讨厌分布式事务
阅读排行:
· 那些年我们一起追过的Java技术,现在真的别再追了!
· 还在手写JSON调教大模型?.NET 9有新玩法
· 为大模型 MCP Code Interpreter 而生:C# Runner 开源发布
· 面试时该如何做好自我介绍呢?附带介绍样板示例!!!
· JavaScript 编年史:探索前端界巨变的幕后推手
more_horiz
keyboard_arrow_up light_mode palette
选择主题
点击右上角即可分享
微信分享提示