题目
我们知道,整数做除法时,有时得到有限小数,有时得到无限循环小数。
如果我们把有限小数的末尾加上无限多个0,它们就有了统一的形式。
本题的任务是:在上面的约定下,求整数除法小数点后的第n位开始的3位数。
输入
一行三个整数:a b n,用空格分开。a是被除数,b是除数,n是所求的小数后位置(0<a,b,n<1000000000)
输出
一行3位数字,表示:a除以b,小数后第n位开始的3位数字。
样例输入
1 8 1
样例输出
125
解题思路
暴力解。
(我开始写的很复杂,还想着如何判断循环小数。。。)
难点
关于运行时间的缩短是本题难点,只需用到求余和乘法的交换律即可,如((a*10%b)*10%b)*10%b…(n次)等价于(10n%b),从而减少了乘法的次数,可以在所需要取的小数点位数很大时,节约运行时间。
代码
看了大佬的解法,把每一次乘上的10改为1010,运行时间从1000+ms降到100+ms,满分代码如下:
#include<stdio.h>
#define ten 10000000000
int main()
{
long int a,b,n,temp,k=1;
scanf("%ld %ld %ld",&a,&b,&n);
a%=b;
while (k<(n-10)){
a = a*ten%b;
k+=10;
}
for (k;k<(n+3);k++)
{
temp = (a*10)/b;
if (k>=n)
printf("%ld",temp);
a = (a*10)%b;
}
return 0;
}
错误代码
主要思路是枚举然后验证是否存在循环数组,判定的标准是个人随机设定的阈值:如果长度为j的数组重复出现10次,那么就判定为循环数组;这种人为设定的阈值科学性不够,在多次调整len和阈值threshold之后,得分大概在75左右:(最后附上了C语言网测试用例,供需要的小伙伴调试)
#include<bits/stdc++.h>
#define len 20000000
using namespace std;
char b[len];
vector <char> p;
int threshold = 10;//寻找是否有重复的最长长度
int min(int a, int b){
return (a>b)?b:a;
}
long int atoi(char a[]){
int i,lena = strlen(a);
long int num = 0;
for (i=0;i<lena;i++)
num+=(a[i]-48)*pow(10,lena-1-i);
return num;
}
void itoa(long int a){
int k = 0;
char t[len];
while (a!=0){
t[k++] = a%10+48;
a/=10;
}
for (int i=0;i<k;i++)
b[i] = t[k-1-i];
b[k++] = '0';//末尾补0,为下一位除法算小数做准备
b[k] = '\0';
}
int isrepeated(char a[], int lena){
int j,i,k,y=1;//y代表是否找到重复
for (j=threshold;j>=1;j--)
{
for(i=lena-1;i>(len-1-j);i--)//每j个一次循环
{
for (k=i;k>=(i-10*j);k-=j)//如果有10次重复出现就认为是重复的
{
if (a[k]!=a[k-j])
{
y = 0;
break;
}
}
if (y==0)//不需要再验证,当前的间隔不是循环的周期
break;
}
if (y==1)//找到了
return j;//返回循环的节律
}
return 0;
}
int main()
{
int i,j,n,cs,num=0,k=0;//k记录小数点后位数数目
int circle = 0;//循环小数
long int temp;
char a[len],cha='0';
scanf("%s %d %d",a,&cs,&n);
temp = atoi(a)%cs;//因为只需要小数部分,为了方便起见直接取余数
itoa(temp);
k = 1;//小数后第一位
while (k!=min((n+3),len)){
a[k++] = atoi(b)/cs+48;
temp = atoi(b)%cs;
itoa(temp);
if (k>(len/10))
{
circle = isrepeated(a,k);
if (circle>0)
{
for (j=k-circle;j<k;j++)
p.push_back(a[j]);
break;
}
}
}
if (circle!=0)
{
i = (n-k-circle)%circle;
j = (n+1-k-circle)%circle;
temp = (n+2-k-circle)%circle;
printf("%c%c%c",p[i],p[j],p[temp]);
}
else
printf("%c%c%c",a[n],a[n+1],a[n+2]);
return 0;
}
测试用例