Three Permutations

题目

#include<iostream>
#include<algorithm>
#include<numeric>//accumulate(be,en,0)
#include<cstring>//rfind("string"),s.find(string,begin)!=s.npos,find_first _of(),find_last_of()
#include<string>//to_string(value),s.substr(int begin, int length);
#include<cstdio>
#include<cmath>
#include<vector>//res.erase(unique(res.begin(), res.end()), res.end()),reverse(q.begin(),q.end());
#include<queue>//priority_queue(big)  /priority_queue<int, vector<int>, greater<int>> q(small)
#include<stack>
#include<map>//unordered_map
#include<set>//iterator,insert(),erase(),lower(>=)/upper_bound(>)(value)/find()return end()
#include<unordered_map>
#include<unordered_set>
//#include<ext/pb_ds/assoc_container.hpp>//gp_hash_table
//#include<ext/pb_ds/hash_policy.hpp>
//using namespace __gnu_pbds;
#define int long long//__int128 2^127-1(GCC)
#define PII pair<int,int>
#define f first
#define s second
using namespace std;
const int inf = 1e17, N = 1e5 + 5;
int disa[N][3], disb[N][3], disc[N][3];
int lena[3], lenb[3], lenc[3];
int exgcd(int a, int b, int& x, int& y)
{
	if (b == 0) {
		x = 1, y = 0;
		return a;
	}
	int d = exgcd(b, a % b, x, y);
	int z = x;
	x = y;
	y = z - y * (a / b);
	return d;
}
int excrt(int m[], int r[])//中国剩余定理模板
{
	int m1, m2, r1, r2, p, q;
	m1 = m[0], r1 = r[0];
	for (int i = 1; i < 3; i++) {
		m2 = m[i], r2 = r[i];
		int d = exgcd(m1, m2, p, q);
		if ((r2 - r1) % d != 0) return -1;
		p = p * (r2 - r1) / d;
		p = (p % (m2 / d) + (m2 / d)) % (m2 / d);
		r1 = m1 * p + r1;
		m1 = m1 * m2 / d;
	}
	return (r1 % m1 + m1) % m1;
}
int solve(int x, int y, int z,int wc)
{
	if (disa[x][wc] == -1 || disb[y][wc] == -1 || disc[z][wc] == -1) return inf;
//如果某个状态到达不了就返回inf
//后面设他们最小值q
//q=dis(mod len)中国剩余定理
	int m[] = { lena[wc],lenb[wc],lenc[wc] };
	int r[] = { disa[x][wc],disb[y][wc],disc[z][wc] };
	int A = excrt(m, r);//如果中国剩余定理无解的话返回-1其他情况就返回他们的解
	return A == -1 ? inf : A;
}
signed main()
{
	ios_base::sync_with_stdio(0); cin.tie(0), cout.tie(0);
	int n;
	cin >> n;
	vector<int>a(n + 5), b(n + 5), c(n + 5);
	for (int i = 1; i <= n; i++) cin >> a[i];
	for (int i = 1; i <= n; i++) cin >> b[i];
	for (int i = 1; i <= n; i++) cin >> c[i];

	vector<int>abc(n + 5), bca(n + 5), cab(n + 5);
//记录每一个数经过3次迭代后所能到达的状态
	for (int i = 1; i <= n; i++) abc[i] = a[b[c[i]]];
	for (int i = 1; i <= n; i++) bca[i] = b[c[a[i]]];
	for (int i = 1; i <= n; i++) cab[i] = c[a[b[i]]];

	memset(disa, -1, sizeof disa);
	memset(disb, -1, sizeof disb);
	memset(disc, -1, sizeof disc);
//将a,b,c分成3组分别是3*k(0),3*k+1(1),3*k+2(2)
//因为它为n个数所以最终经过3*k次迭代必回回到之前标记过的某个数组
//len代表经过k次循环可以会到原来
	for (int i = 1; disa[i][0] == -1; i = abc[i], lena[0]++) disa[i][0] = lena[0];
	for (int i = 1; disb[i][0] == -1; i = bca[i], lenb[0]++) disb[i][0] = lenb[0];
	for (int i = 1; disc[i][0] == -1; i = cab[i], lenc[0]++) disc[i][0] = lenc[0];

	for (int i = a[1]; disa[i][1] == -1; i = abc[i], lena[1]++) disa[i][1] = lena[1];
	for (int i = b[1]; disb[i][1] == -1; i = bca[i], lenb[1]++) disb[i][1] = lenb[1];
	for (int i = c[1]; disc[i][1] == -1; i = cab[i], lenc[1]++) disc[i][1] = lenc[1];

	for (int i = a[b[1]]; disa[i][2] == -1; i = abc[i], lena[2]++) disa[i][2] = lena[2];
	for (int i = b[c[1]]; disb[i][2] == -1; i = bca[i], lenb[2]++) disb[i][2] = lenb[2];
	for (int i = c[a[1]]; disc[i][2] == -1; i = cab[i], lenc[2]++) disc[i][2] = lenc[2];

	int t;
	cin >> t;
	while (t--)
	{
		int x, y, z;
		cin >> x >> y >> z;
//分成3*k(0),3*k+1(1),3*k+2(2)去讨论他是否有解,切最小值是多少
		int m0 = solve(x, y, z, 0);
		int m1 = solve(x, y, z, 1);
		int m2 = solve(x, y, z, 2);
		int ans = min({ m0 * 3,m1 * 3 + 1,m2 * 3 + 2 });
		if (ans >= inf) cout << -1 << '\n';
		else cout << ans << '\n';
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值