3.29考试T2 变戏法

题目描述

一开始有\(n\)个除了颜色完全相同的小球。

定义使用一次膜法的效果是重新排列第\(l_i\)个到第\(r_i\)个小球,\(Mogician\)变完\(m\)次膜法后,让\(Mengbier\)猜最终的顺序。

最终,\(Mengbier\)全部猜错了。\(Mengbier\)怀疑\(Mogician\)作弊了,但他没有证据,所以他只好向你求助。

\(Mengbier\)给定了\(n\)个小球的初始状态,以及\(m\)次膜法的范围\(l_i\)\(r_i\)

\(Mogician\)给出了最终的状态,你需要判断\(Mogician\)是否作弊了,即是否可以从初始状态转移到最终状态。

题解

考虑如果两个小球颜色相同而且可以转移到最终状态的话,那么他们一定可以不改变相对位置就转移到最终状态,证明:假设他们改变了相对位置变成了最终状态,那么他们的路径肯定会有交叉,这样就说明路径不交叉肯定可行,也就是说可以不改变相对位置。

这样的话,我们将小球从\(1\)\(n\)依次对应目标状态它对应的小球,记为\(b\)数组。

因为从初始状态到达目标状态可行的话,也就相当于从目标状态到达初始状态可行,所以我们将题目要求转化为是否可以从目标状态转化为初始状态。

这样的话就相当于是是否可以将\(b\)数组变成一个\(1\)\(n\)的有序序列,那么我们每一次操作就相当于排序了,将对应的\(l_i\)\(r_i\)的数从小到大排序,最后扫一遍\(b\)数组判断。

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 1005;
int T, n, m, a[N], b[N], c[N], flag;
vector<int> vec[N];
inline int read()
{
	int x = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * f;
}
void init() {flag = 0; for(int i = 1; i <= 1000; i ++) {c[i] = 0; vec[i].clear();}}
void get_b()
{
	for(int i = 1; i <= n; i ++)
	{
		c[a[i]] ++;
		if(c[a[i]] > (int)vec[a[i]].size()) {flag = 1; return;}
		b[i] = vec[a[i]][c[a[i]] - 1];
	}
}
int main()
{
	T = read();
	while(T -- > 0)
	{
		n = read(); m = read(); init();
		for(int i = 1; i <= n; i ++) a[i] = read();
		for(int i = 1, x; i <= n; i ++) {x = read(); vec[x].push_back(i);}
		get_b(); if(flag == 1) {puts("NIE"); continue;}
		for(int i = 1, l, r; i <= m; i ++)
		{
			l = read(); r = read();
			sort(b + l, b + r + 1);
		}
		for(int i = 1; i <= n; i ++) if(b[i] != i) {flag = 1; break;}
		if(flag == 1) puts("NIE");
		else puts("TAK");
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/Sunny-r/p/12592417.html
T2