当前位置: 首页 > news >正文

【题解】AtCoder At_abc399_d [ABC399D] Switch Seats

题目大意

请点击 这里 查看原题面。

有一个长度为 2 ⋅ N 2\cdot N 2N 的序列 A A A,其中 1 , 2 , … , N 1,2,\dots,N 1,2,,N 各出现了两次。现在要找满足如下条件的数对 ( a , b ) (a,b) (a,b) 的个数:

  • a a a 的两次出现不相邻。
  • b b b 的两次出现不相邻。
  • 交换一个 a a a 和一个 b b b 的位置任意多次之后,可以使两个 a a a 和 两个 b b b 相邻。

有多测,且 1 ≤ N ≤ 2 ⋅ 1 0 5 1\le N\le 2\cdot 10^5 1N2105

思路

N N N 的值很大,对于每组数据,我们需要一个时间复杂度为 O ( N ) O(N) O(N),总时间复杂度 O ( ∑ 1 T N ) O(\sum_1^T N) O(1TN)。考虑只枚举二元组中的一个数,通过计算得到第二个数并验证。为了更高效、更方便,我们不妨记录一下 1 1 1 N N N 在数组中两次出现的位置。实际上,直接开两个数组就可以维护,我使用了 vector,一个动态数组,虽然浪费空间,但是代码难度不高。

我们可以发现,如果想要满足第三条要求,那么 a a a b b b 需要满足以下条件:

  • a a a 的第一次出现位置和 b b b 的第一次出现位置相邻。
  • a a a 的第二次出现位置和 b b b 的第二次出现位置相邻。

我们需要规定一个“限制”或者“顺序”来避免重复统计。每次只统计第一次出现在 a a a 后面且相邻的 b b b,然后判断第二次是否相邻。但是还有一个小细节:当数据中出现形容 1 2 1 2 的时候,程序遍历到 1 1 1,统计了一次,然后遍历到 2 2 2,又会统计一次。但这是错误的,因为这相当于是调用了两次 1 1 1 的第二个位置。所以我们要小心这个问题。

代码

// 评测记录:https://atcoder.jp/contests/abc399/submissions/64303061
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int t, n, a[400010]; // 注意数组大小
vector<int> p[200010]; // p 记录位置

bool check(int x, int y) // 判断两个位置是否相邻
{
	return abs(x - y) == 1;
}

int main()
{
	cin >> t;
	while (t--)
	{
		cin >> n;
		for (int i = 1; i <= n; i++)
			p[i].clear(); // 多测初始化
		for (int i = 1; i <= n * 2; i++)
		{
			cin >> a[i];
			p[a[i]].push_back(i);
		}
		long long ans = 0;
		for (int i = 1; i <= n; i++)
		{
			if (check(p[i][0], p[i][1]))
				continue; // 两个 a 相邻
			int j = a[p[i][0] + 1];
			if (p[j][0] != p[i][0] + 1)
				continue; // 细节处理
			if (check(p[j][0], p[j][1]))
				continue; // 两个 b 相邻
			if (check(p[i][1], p[j][1]))
				ans++; // 第二次出现的位置相邻就统计答案
		}
		cout << ans << endl;
	}
	return 0;
}

总结

这道题难度不大,个人感觉是 普及 / 提高 − \color{gold}普及/提高- 普及/提高 左右。最后,希望这篇题解对你有帮助,如有想法欢迎评论或私信提出!

http://www.dtcms.com/a/98763.html

相关文章:

  • .NET开发基础知识21-30
  • [GXYCTF2019]禁止套娃1 [GitHack] [无参数RCE]
  • Matplotlib基本使用
  • 数据库监控 | openGauss监控解析
  • 小程序API —— 56页面处理函数 - 下拉刷新
  • 前端常问的宏观“大”问题详解(二)
  • 编译原理课设工作日志
  • 一些练习 C 语言的小游戏
  • 探索Scala基础:融合函数式与面向对象编程的强大语言
  • 在 Unreal Engine 5 中制作类似《鬼泣5》这样的游戏时,角色在空中无法落地的问题可能由多种原因引起。
  • C++作用域辨识详解
  • 高等数学-第七版-上册 选做记录 习题7-4
  • linux基本命令(1)--linux下的打包命令 -- tar 和gzip
  • 电子电气架构 --- 域控架构下,汽车连接器的挑战和变化
  • Ethernet/IP转Modbus剖析库卡机器人同S7-1200PLC双向通讯的技术
  • OpenAI API - Realtime 实时
  • 高速电路中的存储器应用与设计四
  • 【JavaScript】合体期功法——DOM(一)
  • Python 序列构成的数组(元组不仅仅是不可变的列表)
  • 质因数个数--欧拉函数中统计纯素数
  • 直播推流全面指南
  • 【设计模式】单例模式
  • 安卓分发平台一站式APP应用内测平台
  • ros2--功能包
  • 如何备份你的 Postman 所有 Collection?
  • 0329-项目(添加 删除 修改)
  • Java内存中的Heap(堆)的作用
  • <背包问题>
  • Java多线程:(2)通过实现Runnable接口创建线程
  • shell脚本--MySQL简单调用