1035 最长的循环节
10进制的小数如果为无限循环小数,则存在一个循环节,求<=n的数中,倒数循环节长度最长的那个数,假如存在多个最优的答案,输出所有答案中最大的那个数。
1/6= 0.1(6) 循环节长度为11/7= 0.(142857) 循环节长度为61/9= 0.(1) 循环节长度为1
循环小数的性质:
如果循环小数的每个循环节长度为偶数,(记为2K),那么循环节中第i(1<=i<=k)个数字 + 第(i+k)个数字之和为9;
如果p是质数,并且d是1/p的循环节的位数,则d可以整除p−1;
如果1≤b<a, a没有2或者5的质因数,并且a与b互质,那么b/a的循环节位数等于:min{e∈N:10^e≡1(mod a)} 。
如果1≤b<a, a没有2或者5的质因数,并且a与b互质,那么b/a的循环节位数必整除ψ(a)(即a的欧拉函数)。
如果n,m≥3 2和5都不整除mn,并且n与m是互质的正整数,则1/mn的循环位数是1/n与1/m循环小数位数的最小公倍数;
…………,其他定理可以参考论文。
以下是学习笔记:
上面说到的第三条性质主要是用于求一个分数的循环节的长度,如果符合没有2或者5的质因数,就利用上面公式求解,如果不符合就将2或者5的质因子提出然后利用上面的定理。
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string.h>
#include <vector>
using namespace std;
const int Maxn = 1008;
struct table{
int max_id;
int max_val;
}note[Maxn];
int gcd(int a){
int i=1;
int p = 0;
while(1){
i = i*10%a;
p++;
if(i==1){
return p;
}
}
}
int jian(int a){
while(a%5==0){
a = a/5;
}
while(a%2==0){
a = a/2;
}
return a;
}
int n;
int main(){
for(int i=0;i<Maxn;i++){
note[i].max_id = note[i].max_val = 0;
}
note[10].max_id = 7;
note[10].max_val = 6;
while(~scanf("%d",&n)){
if(note[n].max_id){
printf("%d\n",note[n].max_id);
continue;
}
for(int i=11;i<=n;i++){
if(note[i].max_id!=0)
continue;
note[i].max_id = note[i-1].max_id;
note[i].max_val = note[i-1].max_val;
if(i%2==0||i%5==0){
int temp = jian(i);
if(temp==note[i].max_id){
note[i].max_id = temp;
}
}
else{
int temp = gcd(i);
if(temp>=note[i].max_val){
note[i].max_val = temp;
note[i].max_id = i;
}
}
}
printf("%d\n",note[n].max_id);
}
return 0;
}