首页 > 其他分享 >CodeForces 1882E2 Two Permutations (Hard Version)

CodeForces 1882E2 Two Permutations (Hard Version)

时间:2023-10-11 15:26:20浏览次数:35  
标签:Hard int Permutations CodeForces v1 v2 排列 ldots size

洛谷传送门

CF 传送门

如何评价,模拟赛搬了一道,前一天晚上代码写了一半的题。


考虑如何让操作次数最小。发现直接做太困难了。根本原因是,一次操作对序列的影响太大了。考虑做一些转化,减少一次操作对序列的影响。

仍然先考虑一个排列怎么做。

不知道为什么可以想到在排列前面添加特殊字符 \(0\) 变成 \(\{0, p_1, p_2, \ldots, p_n\}\),实际意义是真正的排列是从 \(0\) 的位置开始循环往右读形成的排列。我们每次操作相当于把 \(0\) 和一个数交换,目标是把排列变成 \(\{0, 1, 2, \ldots, n\}, \{n, 0, 1, \ldots, n - 1\}, \{n - 1, n, 0, \ldots, n - 2\}\) 等等其中之一。不失一般性,设要变成 \(\{0, 1, 2, \ldots, n\}\),若不是可以把排列重编号。

这样就好办了。我们连边 \(i \to p_i\),转化成置换环考虑。设此时排列的特殊字符为 \(x = p_0\)(因为重标号过了,所以特殊字符不一定是 \(0\))。设 \(q_i\) 为 \(i\) 的前驱,等价于 \(q_{p_i} = i\)。那么此时我们可以选择任意一个点,把它和 \(q_x\) 的出边(\(p\) 值)交换。

我们首先处理 \(x\) 所在的环。先把 \(q_x\) 和 \(q_{q_x}\) 交换,这样 \(q_x\) 会变成自环,原来的 \(q_{q_x}\) 变成了现在的 \(q_x\)。不断这样操作直到 \(x\) 变成自环。

然后我们操作不包含 \(x\) 的环。显然自环不需要被操作,否则设环上任意一点编号为 \(i\)。先把 \(x\) 和 \(i\) 交换,相当于把这个环塞入 \(x\),转成包含 \(x\) 的环的情况做。

设环长分别为 \(l_1, l_2, \ldots, l_k\),编号为 \(1\) 的环是 \(x\) 所在的环。那么操作次数是:

\[l_1 - 1 + \sum\limits_{i = 2}^k [l_i > 1] (l_i + 1) \]

枚举目标排列是 \(\{0, 1, 2, \ldots, n\}, \{n, 0, 1, \ldots, n - 1\}, \{n - 1, n, 0, \ldots, n - 2\}\) 等等的其中一个,取最小值即可。

考虑两个排列。对两个排列分别做一遍上面的过程。对于奇偶性相同的两个操作序列,我们仍然可以不断往短的操作序列补 \(1, n\) 直到它们长度相等。对于奇偶性不同的两个操作序列,因为我们每种目标排列都考虑过了,所以它们不优。那只需要分奇偶性求出每个排列的最短奇数次操作和最短偶数次操作,取最小值即可。

构造直接按上面的模拟即可。

时间复杂度 \(O(n^2)\)。

code
// Problem: E2. Two Permutations (Hard Version)
// Contest: Codeforces - Codeforces Round 899 (Div. 2)
// URL: https://codeforces.com/problemset/problem/1882/E2
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 2510;

int n, m, a[maxn], b[maxn], p[maxn], q[maxn];
bool vis[maxn];

inline int calc(int *a, int n, int pos) {
	mems(vis, 0);
	for (int i = 0; i <= n; ++i) {
		p[i] = (a[i] + pos) % (n + 1);
	}
	int ans = 0;
	for (int i = 0; i <= n; ++i) {
		if (vis[i]) {
			continue;
		}
		int u = i, cnt = 0;
		do {
			vis[u] = 1;
			u = p[u];
			++cnt;
		} while (u != i);
		if (i == 0) {
			ans += cnt - 1;
		} else if (cnt > 1) {
			ans += cnt + 1;
		}
	}
	return ans;
}

inline void oper(int x, int y) {
	int u = p[x], v = p[y];
	swap(p[x], p[y]);
	swap(q[u], q[v]);
}

inline void work(int *a, int n, int pos, vector<int> &S) {
	mems(vis, 0);
	for (int i = 0; i <= n; ++i) {
		p[i] = (a[i] + pos) % (n + 1);
	}
	for (int i = 0; i <= n; ++i) {
		q[p[i]] = i;
	}
	int x = 0;
	while (x != p[x]) {
		int t = q[x];
		vis[x] = vis[t] = 1;
		oper(x, t);
		S.pb((t - x + n + 1) % (n + 1));
		x = t;
	}
	for (int i = 0; i <= n; ++i) {
		if (p[i] == i || vis[i]) {
			continue;
		}
		oper(x, i);
		S.pb((i - x + n + 1) % (n + 1));
		x = i;
		while (x != p[x]) {
			int t = q[x];
			vis[x] = vis[t] = 1;
			oper(x, t);
			S.pb((t - x + n + 1) % (n + 1));
			x = t;
		}
	}
}

void solve() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i) {
		scanf("%d", &a[i]);
	}
	for (int i = 1; i <= m; ++i) {
		scanf("%d", &b[i]);
	}
	int ap1 = -1, ap2 = -1, bp1 = -1, bp2 = -1;
	int am1 = 2e9, am2 = 2e9, bm1 = 2e9, bm2 = 2e9;
	for (int i = 0; i <= n; ++i) {
		int t = calc(a, n, i);
		if (t & 1) {
			if (t < am1) {
				am1 = t;
				ap1 = i;
			}
		} else {
			if (t < am2) {
				am2 = t;
				ap2 = i;
			}
		}
	}
	for (int i = 0; i <= m; ++i) {
		int t = calc(b, m, i);
		if (t & 1) {
			if (t < bm1) {
				bm1 = t;
				bp1 = i;
			}
		} else {
			if (t < bm2) {
				bm2 = t;
				bp2 = i;
			}
		}
	}
	int ans = min(max(am1, bm1), max(am2, bm2));
	if (ans > 1e9) {
		puts("-1");
		return;
	}
	vector<int> v1, v2;
	if (ans == max(am1, bm1)) {
		work(a, n, ap1, v1);
		work(b, m, bp1, v2);
	} else {
		work(a, n, ap2, v1);
		work(b, m, bp2, v2);
	}
	while (v1.size() < v2.size()) {
		v1.pb(1);
		v1.pb(n);
	}
	while (v2.size() < v1.size()) {
		v2.pb(1);
		v2.pb(m);
	}
	printf("%d\n", (int)v1.size());
	for (int i = 0; i < (int)v1.size(); ++i) {
		printf("%d %d\n", v1[i], v2[i]);
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:Hard,int,Permutations,CodeForces,v1,v2,排列,ldots,size
From: https://www.cnblogs.com/zltzlt-blog/p/17757247.html

相关文章

  • Codeforces Round 834 (Div. 3)
    CodeforcesRound834(Div.3) A-Yes-Yes?思路:判断每种情况即可#include<bits/stdc++.h>usingnamespacestd;//#defineintlonglong//#defineint__int128#definedoublelongdoubletypedefpair<int,int>PII;typedefpair<string,int>PSI;typed......
  • Educational Codeforces Round 156 A-D
    A.SumofThree思路1:1.把数拆成1,2,n-32.如果(n-3)%3==0,那么拆成1,4,n-5,可证明n-3如果可被3整除,那么再左移两位一定除不尽思路2:1.如果n是奇数,那么可取一个数为2,其他两数为相邻数,如果两数其中一位被整除,那么两者往外走2.如果n为偶,那么可取一个数为1,同理上点击查看代码#inclu......
  • Educational Codeforces Round 156 (Rated for Div. 2)
    Preface沉迷Galgame不打CF懒狗闪总出列!这场在大物课上口胡了前四个题,回去写了也都很顺,然后E题本来做不来的,看了眼昨天校队群里的消息就会做了F题什么东西直接弃A.SumofThree当\(n\bmod3\ne0\)时,用\((1,2,z)\)来凑;否则当\(n\bmod3=0\)时,用\((1,4,z)\)来凑#include<cst......
  • Codeforces Round 706 (Div. 2) A. Split it!
    给一个长度为\(n\)的字符串\(s\)。给定一个正整数\(k\)。询问\(s\)能否等于\(a_1+a_2+\cdots+a_k+a_{k+1}+R(a_k)+R(a_{k-1})+\cdots+R(a_{1})\)。其中\(a_i\)代表一个非空字符串,\(R(a_i)\)代表\(a_i\)的\(reverse\)。由于\(a_{k+1}\)......
  • Codeforces Round 707 (Div. 2, based on Moscow Open Olympiad in Informatics) B. N
    按以下\(n\)次操作制作蛋糕。叠上第\(i\)块面包,然后浇上\(a_i\)单位的奶油。可以使当前往下\(a_i\)块面包沾上奶油。输出空格隔开的\(n\)个数,第\(i\)个的\(0/1\)代表第\(i\)块面包是否沾有奶油。比较显然的思路可以进行差分修改。view1#include<bits/std......
  • Codeforces Round 834 (Div. 3)
    A.Yes-Yes?#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongusingpii=pair<int,int>;usingvi=vector<int>;conststringT="Yes";voidsolve(){strings;cin>>s;inti=-1;......
  • Codeforces Round 902 Div 1 (CF 1876)
    A.HelmetsinNightLight按花费sort一下,\(b<p\)就让他用\(b\)的花费告诉别人,剩下的人一开始用\(p\)的花费告诉即可。B.EffectsofAntiPimples发现一个数会被所有它的因数贡献,\(O(n\sqrt{n})\)随便算一算,式子略。C.AutosynthesisSolution1想到了建图但没有完......
  • Educational Codeforces Round 156 (Rated for Div. 2)
    EducationalCodeforcesRound156(RatedforDiv.2)A.SumofThree解题思路:如果\(n\leq6或n=9\),无解。若\(n\%3==0,t=\lfloor\frac{3}{n}\rfloor\):若\(t=0\)构造\(1,4,n-5\)否则,构造\(t-3,t,t+3\)若\(n\%3==1:构造1,2,n-3\)若\(n......
  • Codeforces Round 902 (Div. 2, based on COMPFEST 15 - Final Round)
    目录写在前面ABCDE写在最后写在前面比赛地址:https://codeforces.com/contest/1877。呜呜铃果唱歌太好听了、、、我宣布是第二喜欢的声线,第三喜欢是东北切蒲英,第一喜欢绝赞招募中。这下不得不成为数码推了、、、A答案为\(-\suma_i\)。懒得写代数式子推了,赛时看完题直接......
  • Educational Codeforces Round 152 (Div. 2) D. Array Painting(双指针)
    EducationalCodeforcesRound152(Div.2)D.ArrayPainting//思路:双指针找连续正数段//若段中出现2,则更新两头的0的情况,若为涂色则改为true//若无2,则优先更新左侧0,若左0已经为true,则更新右侧0//数组开头结尾特判#defineintlonglong#defineldlongdoubleusingnam......