当前位置: 代码迷 >> 综合 >> HDOJ 3430 Shuffling
  详细解决方案

HDOJ 3430 Shuffling

热度:58   发布时间:2023-12-06 03:24:46.0

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3430

题意:给我们一个置换,问我们经过几次置换能把一个1~n的初始序列转换成另一个序列,如果不能就输出-1.

第一步,肯定还是暴力找到每一位的循环节以及要达到这个目标状态的偏移量,事实上,我们得到了k个类似于a==b(mod c)这样的方程,k为循环节的个数,那么这就又变成了一个中国剩余定理的问题,这里我们可以直接套用不互质的中国剩余定理模板就好了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 522;
int a[maxn], b[maxn], ta[maxn], tb[maxn];
bool vis[maxn];
LL m[maxn], c[maxn];
void exGcd(LL a,LL b,LL &d,LL &x,LL &y)  
{  if(!b){d=a;x=1;y=0;}  else{exGcd(b,a%b,d,y,x);y-=x*(a/b);}  
}  
LL Chinese_Remainder(LL n,LL a[],LL b[])  
{  LL m1,r1,m2,r2,flag=0,i,d,x,y,c,t;  m1=a[0],r1=b[0];  flag=0;  for(i=1;i<n;i++)  {  m2=a[i],r2=b[i];  if(flag)continue;  exGcd(m1,m2,d,x,y);c=r2-r1;  if(c%d){  flag=1;  continue;  }  t=m2/d; x=(c/d*x%t+t)%t;r1=m1*x+r1;m1=m1*m2/d;  }  if(flag)return -1;  return r1;  
}  
int solve(int n)
{memset(vis, false, sizeof(vis));int cnt = 0;for(int i = 1; i <= n; ++i)if(!vis[i]){int num = 0, t = i;while(!vis[t]){vis[t] = true;ta[++num] = t;tb[num] = b[t];t = a[t];}bool same = false;for(int i = 1; i <= num; ++i)if(tb[i] == ta[1]){same = true;int j = i, k = 1;do{if (tb[j] != ta[k]) same = false;j = j % num + 1;k = k % num + 1;}while(i != j);t = i;break;}if(!same){printf("-1\n");return -1;}m[cnt] = num;c[cnt++] = (num - t + 1) % num;}return cnt;
}
int main()
{int n;while(scanf("%d",&n) && n){for(int i=1; i<=n; i++) scanf("%d",&a[i]);for(int i=1; i<=n; i++) scanf("%d",&b[i]);int cnt;if((cnt = solve(n)) != -1)cout << Chinese_Remainder(cnt,m,c)<<endl;}
}