题目大意
给定 进制下的 ,求出其的混循环部分长度和循环节长度
解题思路
50分思路,模拟乘法+哈希或者
判重
100分思路
首先我们将
约分使其互质,变成下面这一坨
然后混循环部分这一坨很难受,我们可以把它们去掉。
朴素来讲,我们可以让被除数变大以致去掉,但我们同样也可以使除数变小
除数变小有一个规律,即当 的时候那么该小数是一个纯循环小数,我们可以这样去证明
命题:
当 时, 没有混循环部分
证明:
设
的乘法逆元,设
分别是循环节第一次和第二次出现的位置,那么显然
若
,则
(
为
除以
每一次的余数)
这时
故该假设不成立,命题成立
证毕
所以我们可以让
不断除以
直到
即该数为一个有限小数或者纯循环小数,若最后的
则
和
能够完全抵消,则没有循环部分输出0,而混循环部分则为
除的次数
若最后的
,则我们需要计算出循环节的长度,循环节的长度会是
的约数,所以我们可以通过枚举
的约数,在判断一下
,若满足则令
进行转移即可
50分代码
#include<cmath>
#include<cstdio>
#include<cstring>
#define LL long long
#define p 10000007
using namespace std;int last[p],t,num[p];
LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}
LL f,a[2],A,B,K;
int hash(LL x)
{
while(x>p) x-=p;
return x;
}
char c;
LL abs(LL x){return x<0?-x:x;}
inline LL read()
{
f=0;
while(c=getchar(),c<=47||c>=58);f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),c>=48&&c<=57) f=(f<<3)+(f<<1)+c-48;
return f;
}
int find(long long x)
{
int y=hash(abs(x));
while(last[y]&&last[y]!=x) y=hash(++y);
return y;
}
bool init(long long x){return last[find(x)]==x;}
void push(long long x,int z){int y=find(x);last[y]=x;num[y]=z;return;}
int main()
{
t=read();
while(t--)
{
memset(last,0,sizeof(last));
memset(num,0,sizeof(num));
A=read();B=read();K=read();
LL d=gcd(A,B);A/=d;B/=d;
a[1]=A;push(a[1],1);
for(int i=2;;i++)
{
a[i&1]=a[~-i&1]*K%B;
if(!a[i&1])
{
printf("%d 0\n",i-1);
break;
}
else if(!init(a[i&1])) push(a[i&1],i);
else
{
printf("%d %d\n",~-num[find(a[i&1])],i-num[find(a[i&1])]);
break;
}
}
}
return 0;
}
AC代码
#include<cmath>
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;int t,ans1;
LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}
char c;
LL f,A,B,K;
inline LL read()
{
f=0;
while(c=getchar(),c<=47||c>=58);f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),c>=48&&c<=57) f=(f<<3)+(f<<1)+c-48;
return f;
}
void write(LL x){if(x>9) write(x/10);putchar(x%10+48);return;}
LL phi(LL x)//欧拉函数
{
LL y=x;
for(int i=2;i<=sqrt(x);i++) if(x%i==0) {y=y/i*(i-1);do x/=i;while(x%i==0);}
if(x>1) y=y/x*(x-1);
return y;
}
LL mul(LL a,LL b,LL p)//快速幂拆分乘数
{
LL c=0;
for(;b;b>>=1,a=(a<<1)%p) if(b&1) c=(c+a)%p;
return c;
}
LL ksm(LL a,LL b,LL p)//快速幂拆分指数
{
LL ans=1;
for(;b;b>>=1,a=mul(a,a,p)) if(b&1) ans=mul(ans,a,p);
return ans;
}
LL cal(LL A,LL B)//枚举phi(n)的约数
{
LL x=phi(B),y=x;
for(int i=2;i<=sqrt(x);++i)
if(x%i==0)
{
while(!(y%i)&&ksm(A,y/i,B)==1)y/=i;//若满足条件令y=y`
do x/=i;while(x%i==0);
}
if(x>1&&ksm(A,y/x,B)==1)y/=x;
return y;//返回
}
int main()
{
t=read();
while(t--)
{
A=read();B=read();K=read();
LL d=gcd(A,B);A/=d;B/=d;
ans1=0;
while(1)//处理混循环
{
d=gcd(B,K);
if(d==1) break;
B/=d;
ans1++;
}
write(ans1);putchar(32);if(B==1) putchar(48);else write(cal(K,B));//输出
putchar(10);//换行
}
return 0;
}