poj 3358

好题,好解。

//这道题就是求一个分数的2进制小数的循环节长度和起始位置。
//           首先,先对该分数 n/m 化简。
//           n = n / gcd(n, m)
//           m = m / gcd(n, m)
//           n = n mod m
//           接下来就是需要知道一个分数化成k进制小数的方法:
//           for i = 0 to 需要的位数
//                   n = n * k;
//                   bit[i] = n / m;
//                   n = n mod m;
//           可以知道对于某一位的n,设为ni,当到了某一位nj,有ni mod m== nj mod m 时,此时循环节就出现了,长度L = j - i。
//           而aj = (ai * 2 ^ L) mod m 可得 2 ^ L mod m == 1 mod m 。
//			当m与2互质时,由于2 ^ 0 == 1 mod m,2 ^ phi(m) == 1 mod m,循环节的起始点一定为0,即答案的1。
//			.而这里m与2不一定互质,可以通过两边同时消去2的t次幂来达到这个条件,即2 ^ (L - t) == 1 mod (m / 2 ^ t)。
//			可见此时循环节起始点为t,即答案为t + 1。
//           剩下的就是求2 ^ L' = 1 mod m' 了,由于若2 ^ k == 1 mod m',则k整除phi(m'),所以我们可以从小到大枚举phi(m')的因子,即可得到答案。
//============================================================================
// Name        : 3358.cpp
// Author      : 
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
//这道题就是求一个分数的2进制小数的循环节长度和起始位置。
//           首先,先对该分数 n/m 化简。
//           n = n / gcd(n, m)
//           m = m / gcd(n, m)
//           n = n mod m
//           接下来就是需要知道一个分数化成k进制小数的方法:
//           for i = 0 to 需要的位数
//                   n = n * k;
//                   bit[i] = n / m;
//                   n = n mod m;
//           可以知道对于某一位的n,设为ni,当到了某一位nj,有ni mod m== nj mod m 时,此时循环节就出现了,长度L = j - i。
//           而aj = (ai * 2 ^ L) mod m 可得 2 ^ L mod m == 1 mod m 。
//			当m与2互质时,由于2 ^ 0 == 1 mod m,2 ^ phi(m) == 1 mod m,循环节的起始点一定为0,即答案的1。
//			.而这里m与2不一定互质,可以通过两边同时消去2的t次幂来达到这个条件,即2 ^ (L - t) == 1 mod (m / 2 ^ t)。
//			可见此时循环节起始点为t,即答案为t + 1。
//           剩下的就是求2 ^ L' = 1 mod m' 了,由于若2 ^ k == 1 mod m',则k整除phi(m'),所以我们可以从小到大枚举phi(m')的因子,即可得到答案。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;


int t, n, m, GCD, phi, ans1, ans2;
int temp, num;
int fac[1000000];

int gcd(int x, int y){
	int r;
	if(x < y){
		swap(x, y);
	}
	while(x%y){
		r = x%y;
		x = y;
		y = r;
	}
	return y;
}

int euler(int x){
	int y = (int)sqrt(x+0.5);
	int curans = x;
	for(int i = 2;i <= y;i++){
		if(x%i == 0){
			curans = curans/i*(i-1);
			while(x%i == 0){
				x /= i;
			}
		}
	}
	if(x > 1){
		curans = curans/x*(x-1);
	}
	return curans;
}

int quickpow(int m, int n, int k){
	int b = 1;
	while(n > 0){
		if(n&1){
			b = (long long)b*m%k;
		}
		n >>= 1;
		m = (long long)m*m%k;
	}
	return b;
}





int main(){
//	printf("%d\n", euler(5));
	freopen("a.txt", "r", stdin);
	int T = 0;
	while(scanf("%d/%d", &n, &m)!=EOF){
		T++;
		GCD = gcd(n, m);
//		printf("%d\n", GCD);
		n /= GCD;
		m /= GCD;
//		printf("%d %d\n", n, m);
		t = 0;
		while(m%2 == 0){
			t++;
			m /= 2;
		}
		ans1 = t+1;
		phi = euler(m);
		if(phi == 1){
			ans2 == 1;
		}
		else{
			num = 0;
			for(int i = 1;i*i <= phi;i++){
				if(phi%i == 0)
				{
					fac[num++] = i;
					fac[num++] = phi/i;
				}
			}
			sort(fac, fac+num);
//			printf("%d\n", num);
			for(int i = 0;i < num;i++){
//				printf("%d\n", fac[i]);
				temp = quickpow(2, fac[i], m);
//					printf("i: %d phi: %d %d\n", i, phi, temp);
				if(temp == 1){
//					printf("%d\n\n", ans2);
					ans2 = fac[i];
					break;
				}
			}
		}
		printf("Case #%d: ", T);
		printf("%d,%d\n", ans1, ans2);
	}
	return 0;
}

  

posted @ 2011-07-28 10:25  KOKO's  阅读(843)  评论(0编辑  收藏  举报