2021-2022-1 ACM集训队每月程序设计竞赛(2)-问题 G: 轮换的复合 - 题解

题意
首先说一下什么是轮换吧,就给出一个 P = ( a , c , d , e ) P=(a,c,d,e) P=(a,c,d,e),那么对应的置换就是 ( a b c d e c b d e a ) \begin{gathered} \begin{pmatrix} a & b & c & d& e \\ c & b & d & e & a \end{pmatrix} \end{gathered} (acbbcddeea)其中 a a a 的下面对应的是 P P P a a a 的下一个,也就是 c c c,而 b b b P P P 中没有出现过,因此它下面对应的是它自己。特别的, e e e 的下一个是 a a a,也就是说最后一个的下一位是第一个。

而两个置换的复合,就像题面中说明的那样,用第一个置换的第二行和第二个置换的第一行相对应,然后形成一个新的置换,这个在题面中已经解释的很详细了。

思路
首先我承认,我脑子有坑,一开始想把这道题搞成矩阵快速幂,然后东哥一句棒喝,让我认识到离散数学是真的没有学透……

首先,置换满足结合律(证明略),也就是说可以先算后面的 m m m P 2 P_{2} P2 的置换,最后再和 P 1 P_{1} P1 算一次就够了。

然后我们可以发现,一个 P 2 P_{2} P2的话,第一行每一个元素对应的是 P P P 中相应位置的下一个;而 P 2 ∗ P 2 P_{2}*P_{2} P2P2,相当于每一个元素对应的是 P P P 中相应位置的下一个的下一个,即 P P P 整体向右对应两位。如果是 m m m P 2 P_{2} P2的话呢?自然是每一个数都对应它相应位置的之后 m % k 2 m\%k_{2} m%k2个,毕竟这是一个循环,如果 k 2 k_{2} k2 P 2 P_{2} P2 相复合的话,那相当于根本没没有移动过。

那接下来的话就很简单了,搞出来 m m m P 2 P_{2} P2相复合后的结果,然后 P 1 P_{1} P1再与之复合即可。

时间复杂度 O ( n ) O(n) On

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 10;
int n, m, k1, k2;
int s[N], d[N];
int num[N];

signed main() {
	scanf("%lld %lld", &n, &m);

	for (int i = 1; i <= n; i++) {
		s[i] = i;
		d[i] = i;
	}

	scanf("%lld", &k1);
	for (int i = 0; i < k1; i++)
		scanf("%lld", &num[i]);

	for (int i = 0; i < k1; i++)
		s[num[i]] = num[(i + 1) % k1];

	scanf("%lld", &k2);
	for (int i = 0; i < k2; i++)
		scanf("%lld", &num[i]);
	m %= k2;

	for (int i = 0; i < k2; i++)
		d[num[i]] = num[(i + m) % k2];

	for (int i = 1; i <= n; i++)
		s[i] = d[s[i]];

	for (int i = 1; i <= n; i++)
		printf("%lld ", i);
	printf("\n");
	for (int i = 1; i <= n; i++)
		printf("%lld ", s[i]);

	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值