蓝桥历届真题——小数第n位 (循环小数的循环节)

试题 历届试题 小数第n位 循环小数的循环节
时间限制:1.0s 内存限制:256.0MB

问题描述
  我们知道,整数做除法时,有时得到有限小数,有时得到无限循环小数。
  如果我们把有限小数的末尾加上无限多个0,它们就有了统一的形式。
  本题的任务是:在上面的约定下,求整数除法小数点后的第n位开始的3位数。
  
输入格式
  一行三个整数:a b n,用空格分开。a是被除数,b是除数,n是所求的小数后位置(0<a,b,n<1e9)
输出格式
  一行3位数字,表示:a除以b,小数后第n位开始的3位数字。
  
样例输入
1 8 1
样例输出
125

样例输入
1 8 3
样例输出
500

样例输入
282866 999000 6
样例输出
914

思路1【15ms做法】:用x和y表示分子和分母,先求出整数部分x div y和余数部分x mod y,那么小数部分就是重复将余数部分乘以10再进行整除运算和求余运算,直到出现循环或余数为0时结束。不妨从余数入手,因为小数部分整除的结果是由上一次运算的余数决定的,如果某一次运算产生的余数跟前面产生的余数相同,则说明循环开始。

#include <bits/stdc++.h>
#define ll long long 
using namespace std;
const int maxn = 1e6+10;
ll p[maxn],q[maxn],l[maxn]; //分别标记余数是否出现,存放小数结果和循环部分 
ll a,b,n;

int main()
{
    
    
    scanf("%lld %lld %lld",&a,&b,&n);
    ll rest = a%b; //余数 
    for(int i=0; i<maxn; i++) {
    
    
    	p[i] = -1;
    	q[i] = 0;
	}
	
	ll len = 0;
	while(rest!=0 && p[rest]==-1) {
    
     // 余数不为 0(未除尽)并且第一次出现 
		p[rest] = len++; // 标记余数为第几个,p[rest]为不循环部分的长度 
		rest *= 10; 
		q[len] = rest/b; // 小数的下一位,q[1]为小数后第一位,len可以看作结果的长度 
		rest %= b; //余数更新 
	} 
	
	// 若是因为rest==0而退出循环,表示除得尽
	// 若是因为p[rest]!=-1退出,说明出现了重复的余数,除不尽 
	if(rest==0) {
    
    
		p[rest] = len;
		q[++len] = 0;
	}
	
	int len_nl = p[rest]; //不循环的长度
	int len_l = len-len_nl; //循环长度=总长度-不循环长度
	
	if(n>len_nl) {
    
     //输出的位置在循环部分 
		l[0] = q[len]; // 为方便输出,将循环部分放进l[],将其最后一位放在l[0]
		for(int i=1; i<len_l; i++)
		    l[i] = q[len_nl+i];
		n -= len_nl; //因为是输出循环部分的数字,所以砍掉前面的
		cout<< l[n%len_l] << l[(n+1)%len_l] << l[(n+2)%len_l] <<endl;
	} 
	
	else if(n+2<=len_nl) cout<<q[n]<<q[n+1]<<q[n+2]<<endl;
	
	else if(n+1==len_nl) cout<<q[n]<<q[n+1]<<q[(n+2)%len_l]<<endl;
	
	else if(n==len_nl) cout<<q[n]<<q[(n+1)%len_l]<<q[(n+2)%len_l]<<endl;
	
	return 0;
}

思路2【156ms做法】:模拟一下除法,但是如果直接一个个相除,时间复杂度会过高,此时应该想办法加速:每次循环后乘以10的n次方,同时小数快速前进n位!(思路更加清晰,代码更加简单,就是时间增长到了近十倍 QAQ)

#include <bits/stdc++.h>
#define ll long long
#pragma GCC optimize(3 , "Ofast" , "inline")
using namespace std;

int main()
{
    
    
	ll a,b,n;
	while(cin>>a>>b>>n)
	{
    
    
		while(n-10>0)
		{
    
    
			a *= 1e10; //快速逼近 
			a %= b;
			n -= 10; 
		} 
		
		for(int i=1; i<n+3; i++)
		{
    
    
			a *= 10;
			if(i>=n)  cout<<a/b;
			a%=b;
		}
	}
	puts("");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Luoxiaobaia/article/details/108718362