HDOJ 3430 Shuffling

题目链接: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;
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值