题目描述
我们知道,整数做除法时,有时得到有限小数,有时得到无限循环小数。
如果我们把有限小数的末尾加上无限多个 0,它们就有了统一的形式。
本题的任务是:在上面的约定下,求整数除法小数点后的第 nn 位开始的 3 位数。
输入描述
输入一行三个整数:a\ b\ na b n,用空格分开。aa 是被除数,bb 是除数,nn 是所求的小数后位置(0<a,b,n<10^90<a,b,n<109)
输出描述
输出一行 3 位数字,表示:aa 除以 bb,小数后第 nn 位开始的 3 位数字。
输入输出样例
示例
输入
1 8 1
输出
125
运行限制
最大运行时间:1s
最大运行内存: 256M
// int main(int argc, char *argv[])
// {
// double m, a=1,b=3;
// long long n;
// // scanf("%d%d%lld",&a,&b,&n);
// m=a/b;
// printf("%lf",m);
// return 0;
// }
//开始时企图直接取10^9,10^8这样直接取整求余计算,结果溢出了
后来使用pow,for循环,同样也是溢出导致数据错误
#include <stdio.h>
#include<math.h>
long long a,b,n,c=1000;
int main(){
scanf("%lld%lld%lld",&a,&b,&n);
long long ans=(a*pow(10,n+2)/b);
printf("%lld\n",ans%1000);
//注意%1000不能连续写在一起,不然数据类型会冲突
return 0;
}
#include <stdio.h>
long long a=1,b,n;
int main(){
scanf("%lld%lld%lld",&a,&b,&n);
for(long long i=0;i<n+2;i++)
{
a*=10;
}
long long ans=(a/b)%1000;
printf("%lld\n",ans);
return 0;
}
后来使用了快速幂,但同样因为n的增大同样面临溢出,即使算法更高效也是难以避免数据过大的溢出
先讲解一下快速幂

#include <stdio.h>
#include <stdlib.h>
long long qpow(int x,long long m)
{
long long ans=1;
while(m)
{
if(m&1)
{
ans*=x;
}
// else err
//不能是else,不然你这个进位就没办法执行了
//位置一直都在前进,每次数位挪动也要跟着更新
//x的值才行,所以每次循环都应该自增x
x*=x;
m>>=1;
}
return ans;
}
int main(int argc, char *argv[])
{
long long a,b,n;
scanf("%lld%lld%lld",&a,&b,&n);
printf("%lld",(a*qpow(10,n+2))/b%1000);
return 0;
}
正解
// 本质上是因为幂随n的增大导致长整型的溢出,因此我们必须缩小数据大小
// 同时也是为了提高算法效率同样也需要用快速幂解题
// 我们的qpow函数并没有达到做到直接计算出a^n这个答案,我们仅仅只是为题设服务
//就是输出指定位置的3个数据,将庞大的数据压缩,一边检索一边舍去不要的答案来实现成功输出
#include <stdio.h>
long long a,b,n;
long long qpow(long long x,long long y){
long long res=1;
while(y)
{
if(y&1)
{
res=res*x%(b*1000);
}
y>>=1;
x=x*x%(b*1000);
}
return res;
}
//在快速幂的基础上,取模b*1000;
//在主函数中说过都是从1开始计算的
//这里的1000也是为了直接输出整数答案
//我们先不用1000
// if(y&1){
// res=res*x%(b);
// }
// y>>=1;
// x=x*x%(b);
// {
//假设现在是10/7
//计算得知为1.42857...
//然后10%7=3
//3/7=0.42857....
//可以发现前面的数字一被这个操作去除了
//假设n=3,b=7,a=1
//那么程序开始时,因为是10^(n+2)
//所以n=1时,ans=1000<b*1000
//假设直接带回输出,然后/7
//答案为142,从第一位开始,很合理
//而从第二位,ans=10000>b*1000
//取模可得ans=3000
//a/b=0.142857...
//3000/7=428,第二位,合理
//然后n=3时,快速幂算法得知
//10<b*1000
//10*10^4=100000>b*1000
//取模得到2000
//2000/7=285得到第三位
//实际上是因为取整就是拿了小数点之前的数
//取模就是之后的数,将之后的数*1000就是答案
//而随着你的幂不断增大
//如1变为100
//1/7=0.142857...
//100/7=14.2857...
//数字变大自然而然地会增加整数,减少小数
//因此取模之后小数部分也就自然向后走了
//包括10^4*10^8=10^12也是一样
//保留了res继续取模也是接着取模去除的
int main(){
scanf("%lld%lld%lld",&a,&b,&n);
long long ans=(a*qpow(10,n+2)%(b*1000))/b;
//实际数字a只是倍数,都是在a=1的运算基础上乘上一个倍数,
// 所以再乘a就可以得出想要的结果
//这里还取一次模是因为a会改变qpow中的ans的大小
//同理要重新确定范围,然后取出小数范围,
//最后/b输出小数部分!
printf("%lld\n",ans);
return 0;
}
// 总结:取模相当于分割整数和小数,
// 可以连续取模,不影响最终结果
// 10^(n+2)还有1000都是为了小数点后三位直接输出服务的
//如1000,用不到取模就要10^3/8=125输出结果
//如果用上了取模就要保留千位来输出三位整数
//千位或者以上,全看b的大小,但因为b为除数,
//怎么输出都是3位数字的结果
//题目本质是余数/除数得出小数后位的结果!
//幂的增和a会影响整数范围,决定划分点,b起到分划的作用
//(//1/7=0.142857...
//100/7=14.2857...)
//a%b相当于划定整数和小数范围
//a/b是取到整数的范围
//而a%b是取到了小数的范围,
//但本身是余数,需要再次/b才能转化成小数部分
