您的位置:首页 > 其它

HDOJ 3430 Shuffling

2016-06-28 12:28 211 查看
题目链接: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;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: