Atcoder agc031D

63 篇文章 0 订阅
20 篇文章 0 订阅

漏了一题可还行。。。这个显然是我不会的群论题,虽然也不用太高深的知识,可能说是找规律题更合适。
用置换的符号,可以发现 f ( p , q ) = q ⋅ p − 1 f(p,q)=q\cdot p^{-1} f(p,q)=qp1,这里 ⋅ \cdot 指的是置换的复合。
于是有:

  • a 1 = p a_1=p a1=p
  • a 2 = q a_2=q a2=q
  • a 3 = q p − 1 a_3=qp^{-1} a3=qp1
  • a 4 = q p − 1 q − 1 a_4=qp^{-1}q^{-1} a4=qp1q1
  • a 5 = q p − 1 q − 1 p q − 1 a_5=qp^{-1}q^{-1}pq^{-1} a5=qp1q1pq1
  • a 6 = q p − 1 q − 1 p p q − 1 a_6=qp^{-1}q^{-1}ppq^{-1} a6=qp1q1ppq1
  • a 7 = q p − 1 q − 1 p q p q − 1 = ( q p − 1 q − 1 p ) p ( q p − 1 q − 1 p ) − 1 a_7=qp^{-1}q^{-1}pqpq^{-1}=(qp^{-1}q^{-1}p)p(qp^{-1}q^{-1}p)^{-1} a7=qp1q1pqpq1=(qp1q1p)p(qp1q1p)1
  • a 8 = q p − 1 q − 1 p q p − 1 q p q − 1 = ( q p − 1 q − 1 p ) q ( q p − 1 q − 1 p ) − 1 a_8=qp^{-1}q^{-1}pqp^{-1}qpq^{-1}=(qp^{-1}q^{-1}p)q(qp^{-1}q^{-1}p)^{-1} a8=qp1q1pqp1qpq1=(qp1q1p)q(qp1q1p)1
    A = q p − 1 q − 1 p A=qp^{-1}q^{-1}p A=qp1q1p,那么有 a 7 = A a 1 A − 1 a_7=Aa_1A^{-1} a7=Aa1A1 a 8 = A a 2 A − 1 a_8=Aa_2A^{-1} a8=Aa2A1,于是容易用归纳法证明 a n = A a n − 6 A − 1 ( n > 6 ) a_n=Aa_{n-6}A^{-1}(n>6) an=Aan6A1(n>6)。这样可以快速知道 a k = A ⌊ k − 1 6 ⌋ a ( k − 1 )   m o d   6 + 1 ( A − 1 ) ⌊ k − 1 6 ⌋ a_k=A^{\lfloor \frac{k-1}{6}\rfloor}a_{(k-1) \bmod 6+1}(A^{-1})^{\lfloor \frac{k-1}{6}\rfloor} ak=A6k1a(k1)mod6+1(A1)6k1
    置换的复合,求逆, k k k次幂都是 O ( N ) \mathcal O(N) O(N)的,于是总时间复杂度仍为 O ( N ) \mathcal O(N) O(N)
#include <bits/stdc++.h>

using namespace std;

bool vis[100005];
int now[100005];

struct Per {
  int *num,n;
  Per() {}
  Per(int a):n(a) {num=new int[n+1];}
  Per inv() {
  	Per b(n);
  	for(int i=1;i<=n;i++) b.num[num[i]]=i;
  	return b;
  }
  Per operator * (Per b) {
  	Per c(n);
  	for(int i=1;i<=n;i++) c.num[i]=num[b.num[i]];
  	return c;
  }
  Per operator ^ (int k) {
  	Per b(n);
  	for(int i=1;i<=n;i++) vis[i]=0;
  	for(int i=1;i<=n;i++)
  	  if (!vis[i]) {
  	  	  int x=i,cnt=0;
  	  	  do {
  	  	  	now[++cnt]=x;
  	  	  	vis[x]=1;
  	  	  	x=num[x];
		  } while (x!=i);
		  for(int j=1;j<=cnt;j++) b.num[now[j]]=now[(j+k-1)%cnt+1];
		}
	return b;
  }
};

Per fir[7];

int main() {
  int n,k;
  scanf("%d%d",&n,&k);
  fir[1]=Per(n);
  fir[2]=Per(n);
  for(int i=1;i<=n;i++) scanf("%d",&fir[1].num[i]);
  for(int i=1;i<=n;i++) scanf("%d",&fir[2].num[i]);
  for(int i=3;i<=6;i++) fir[i]=fir[i-1]*fir[i-2].inv();
  Per a=fir[2]*fir[1].inv()*fir[2].inv()*fir[1];
  Per ans=(a^((k-1)/6))*fir[(k-1)%6+1]*(a.inv()^((k-1)/6));
  for(int i=1;i<=n;i++) printf("%d ",ans.num[i]);
  printf("\n");
  return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值