ZOJ 3896 Permutation (JAVA IO, CRT)

题意:

给定n的两个排列A和B,还有置换C,问最少需要对A进行多少次置换C才能变成B,不可能则输出Impossible

思路:

思路是比较好想的,难度在于怎么实现。。

对A中每个数A[i],求出它需要经过多少次置换能变成B[i],如果变不了就Impossible。

然后就是用CRT来合并就是答案了。

涨姿势了。。java的输入挂。。

import java.math.*;
import java.text.*;
import java.util.*;
import java.io.*;


class Scan {
	BufferedReader buffer;
	StringTokenizer tok;
	Scan() {
		buffer = new BufferedReader(new InputStreamReader(System.in));
		tok = null;
	}
	
	boolean hasNext() {
		while(tok == null || !tok.hasMoreElements()) {
			try {
				tok = new StringTokenizer(buffer.readLine());
			} catch(Exception e) {
				return false;
			}
		}
		return true;
	}
	String next() {
		if(hasNext()) return tok.nextToken();
		return null;
	}
	int nextInt() {
		String s = next();
		return Integer.parseInt(s);
	}
	long nextLong() {
		return Long.parseLong(next());
	}
}

public class Main {
	
	public static BigInteger K1, K2;
	
	public static void exgcd(BigInteger a, BigInteger b) {
		if(b.compareTo(BigInteger.ZERO) == 0) {
			K1 = BigInteger.ONE;
			K2 = BigInteger.ZERO;
		}
		else {
			exgcd(b, a.mod(b));
			BigInteger tmp = K1;
			K1 = K2;
			K2 = tmp;
			K2 = K2.subtract(a.divide(b).multiply(K1));
		}
	}
	
	public static void main(String []args) {
		PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
		
		Scan scan = new Scan();
		int N = 50020;
		int a[] = new int[N], b[] = new int[N], c[] = new int[N], n;
		boolean vis[] = new boolean[N];
		int pos[] = new int[N];
		int dep[] = new int[N];
		int x[] = new int[N];
		int t[] = new int[N], val[] = new int[N];
		int mod[] = new int[N];
		
		
		while(scan.hasNext()) {
			n = scan.nextInt();
			
			for(int i = 1; i <= n; ++i) {
				a[i] = scan.nextInt();
				pos[a[i]] = i;
			}
			for(int i = 1; i <= n; ++i)
				b[i] = scan.nextInt();
			for(int i = 1; i <= n; ++i)
				c[i] = scan.nextInt();
			for(int i = 1; i <= n; ++i) {
				vis[i] = false;
				dep[i] = -1;
				mod[i] = -1;
			}
			boolean flag = true;
			
			int tot = 0;
			
			for(int i = 1; i <= n; ++i) {
				if(!vis[a[i]]) {
					int cnt = 0;
					int u = c[i];
					x[++cnt] = a[i];
					dep[a[i]] = 0;
					int d = 0;
					while(u != i) {
						dep[a[u]] = ++d;
						vis[a[u]] = true;
					//	System.out.println("dep " + a[u] + " " + dep[a[u]]);
						x[++cnt] = a[u];
						u = c[u];
					}
					for(int j = 1; j <= cnt; ++j) {
						//System.out.println("x[j] " + x[j]);
						int v = pos[x[j]];
						if(dep[b[v]] == -1) {
							flag = false;
							break;
						}
						val[++tot] = dep[a[v]] - dep[b[v]];
						if(val[tot] < 0) val[tot] += cnt;
						if(mod[cnt] != -1 && mod[cnt] != val[tot]) {
							flag = false;
							break;
						}
						mod[cnt] = val[tot];
					}
					for(int j = 1; j <= cnt; ++j) {
						int v = pos[x[j]];
						dep[a[v]] = -1;
					}
					if(flag == false) break;
				}
			}
			
			if(!flag) {
				System.out.println("Impossible");
				continue;
			}
			
			BigInteger M1 = BigInteger.ONE;
			BigInteger B1 = BigInteger.ZERO;
			
			for(int i = 2; i <= n; ++i) {
				if(mod[i] == -1) continue;
				//System.out.println("i " + i + "mod " + mod[i]);
				BigInteger M2 = BigInteger.valueOf(i);
				BigInteger B2 = BigInteger.valueOf(mod[i]);
				BigInteger g = M2.gcd(M1);
				BigInteger X = B2.subtract(B1);
				if(X.mod(g).compareTo(BigInteger.ZERO) != 0) {
					flag = false;
					break;
				}
				exgcd(M1.divide(g), M2.divide(g));
			//	System.out.println(K1 + " " + K2);
				K1 = K1.multiply(X.divide(g));
				B1 = B1.add(K1.multiply(M1));
				M1 = M1.divide(g).multiply(M2);
				B1 = B1.mod(M1);
				if(B1.compareTo(BigInteger.ZERO) < 0) B1 = B1.add(M1);
			//	System.out.println("B1 M1" + B1 + "  " + M1);
			}
			if(!flag) {
				System.out.println("Impossible");
				continue;
			}
			
			System.out.println(B1);
		}
	}
	
}

 
  


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值