poj 3358

时间:2023-11-25 13:36:26
 /**
大意: 给定小数(p/q),求其循环节的大小和循环节开始的位置
解法: 若出现循环 ai*2^m= aj%p;
即 2^m %p =1
若2与p 互素,则可由欧拉函数的,
不互素,需将其转化为互素的情况,,也就出现了循环节开始位置的差异; 值得学习的地方:
1、
首先,先对该分数 n/m 化简。
temp = gcd(n,m);
// n = n / temp
// m = m / temp
// n = n mod m
// 接下来就是需要知道一个分数化成k进制小数的方法:
// for i = 0 to 需要的位数
// n = n * k;
// bit[i] = n / m;
// 2、
a ^ x % q = 1,对于其任意一个解x ,它的最小解x0 | x 。
在a 与 q 互质的条件下,ψ(q) 是它的一个解。
所以有x0 | ψ(q)这样一个条件,可以先求出q的欧拉函数值ψ(q),再在它的因子中找最小解。
注意中间过程int可能溢出。 **/ #include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;
long long fn[];
long long gcd(long long a,long long b){
if(b==)
return a;
return gcd(b,a%b);
} long long pow(long long a,long long b,long long m){
if(b==)
return ;
long long c =;
a =a%m;
while(b){
if(b&)
c = (long long )c*a%m;
a =(long long )a*a%m;
b>>=;
}
return c;
} long long eular(long long n){
long long m = (long long )sqrt(n+0.5);
long long ans = n;
for(long long i=;i<=m;i++) if(n%i==){
ans = ans/i*(i-);
while(n%i==)
n/=i;
}
if(n>)
ans = ans/n*(n-);
return ans;
} int main()
{
long long n,m;
char c; long long cur =;
while(cin>>n>>c>>m){
int temp = gcd(n,m); // 注意:一上午自己就是因为这个图省劲没有先将gcd(n,m)存起来,,导致后边的m/gcd(n,m) 一直是n与m的最大公约数是1的情况,即m没有得化简。。。
n = n/temp;
m = m/temp;
n = n%m;
long long ans1,ans2;
long long t=;
while(m%==){
m = m/;
t++;
}
ans1 = t+; long long res = eular(m);
if(res==){
ans2 = ;
}else{
long long cnt =;
// cout<<res<<endl;
for(long long i=;i*i<=res;i++)if(res%i==){
fn[cnt++] = i;
fn[cnt++] = res/i;
}
sort(fn,fn+cnt);
for(long long i=;i<cnt;i++){
if(pow(,fn[i],m)==){
ans2 = fn[i];
break;
}
}
}
cout<<"Case #"<<cur++<<": "<<ans1<<","<<ans2<<endl;
}
return ;
}