链接:https://ac.nowcoder.com/acm/contest/548/B
来源:牛客网
题目描述
立华奏在学习初中数学的时候遇到了这样一道大水题:
“设箱子内有 n 个球,其中给 m 个球打上标记,设一次摸球摸到每一个球的概率均等,求一次摸球摸到打标记的球的概率”
“emmm…语言入门题”
但是她改了一下询问方式:设最终的答案为 p ,请输出 p 小数点后 K1
到 K2 位的所有数字(若不足则用 0 补齐)
输入描述:
第一行一个整数 T,表示有 T 组数据。
接下来每行包含四个整数
m,n,K1,K2,意义如「题目描述」所示。
输出描述:
输出 T 行,每行输出
K2−K1+1 个数,表示答案。
注意同行的数字中间不需要用空格隔开。
示例1
输入
复制
5
2 3 2 3
1 7 1 7
2 5 1 3
12345 54321 3 10
12345 54321 100000 100010
输出
复制
66
1428571
400
72601756
78428232175
备注:
1≤m≤n≤109,1≤K1≤K2≤10^9;
0≤K2−K1≤10^5,T≤20。
题解:这是一道模拟除法的题,因为它只求小数点后k1到k2位的数字,所以可以先快速幂求到第k1位的数字,然后模拟除法输出,因为这题的输出有点大,刚开始我就直接tle了,我用了三种解决方法,一种是用 PrintWriter,这个在输出多的时候会加速很多,另外一种就是用StringBuffer存储每一组结果,最后输出,注意用String存储的话也会超时。还有一种是用StringBuilder,这个原理和StringBuffer一样。
使用的StringBuffer类的 附加方法追加字符比字符串使用+操作符添加字符到一个已经存在的字符串后面有效率得多。因为使用+操作符每一次将字符添加到一个字符串中去时,字符串对象都需要寻找一个新的内存空间来容纳更大的字符串,这无凝是一个非常消耗时间的操作。添加多个字符也就意味着要一次又一次的对字符串重新分配内存。使用的StringBuffer类就避免了这个问题
StringBuffer和StringBuilder的区别在于StringBuffer是线程安全的,而StringBuilder不是,但是StringBuilder运行速度更快,所以在单线程程序中推荐用StringBuilder,多线程中用StringBuffer。
这个是用PrintWriter
这个使用StringBuffer
这个用StringBuilder
可以看到用StringBuffer和StringBuilder的速度更快,而且内存使用只有上一种的五分之一不到。算法比赛中都是单线程程序,所以推荐用StringBuilder。
代码1:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//这题输入其实不多,可以直接用Scanner
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
st.nextToken();
int t=(int)st.nval;
while(t-->0){
long n,m;
int k1,k2;
st.nextToken();
m=(int)st.nval;
st.nextToken();
n=(int)st.nval;
st.nextToken();
k1=(int)st.nval;
st.nextToken();
k2=(int)st.nval;
long mul=10;
long sum=1;
int len=k2-k1+1;//最后要输出的位数
k1--;
while(k1!=0){
if((k1&1)!=0)
sum=sum*mul%n;
mul=mul*mul%n;
k1>>=1;
}
sum=m*sum%n*10;
for(int i=0;i<len;sum=sum%n*10,++i){
out.print(sum/n);
}
out.flush(); //注意刷新缓冲区,不然输出会出问题
System.out.println();
}
}
}
代码2:
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
//StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
Scanner sc=new Scanner(System.in);
int t=sc.nextInt();
while(t-->0){
long n,m;
int k1,k2;
m=sc.nextLong();
n=sc.nextLong();
k1=sc.nextInt();
k2=sc.nextInt();
long mul=10;
long sum=1;
int len=k2-k1+1;
k1--;
while(k1!=0){
if((k1&1)!=0)
sum=sum*mul%n;
mul=mul*mul%n;
k1>>=1;
}
sum=m*sum%n*10;
StringBuffer sb = new StringBuffer();
for(int i=0;i<len;sum=sum%n*10,++i){
sb.append(sum/n); //这个比String的+操作符快很多
}
System.out.println(sb);
}
sc.close();
}
}
代码3:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
//StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
//PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
Scanner sc=new Scanner(System.in);
int t=sc.nextInt();
while(t-->0){
long n,m;
int k1,k2;
m=sc.nextLong();
n=sc.nextLong();
k1=sc.nextInt();
k2=sc.nextInt();
long mul=10;
long sum=1;
int len=k2-k1+1;
k1--;
while(k1!=0){
if((k1&1)!=0)
sum=sum*mul%n;
mul=mul*mul%n;
k1>>=1;
}
sum=m*sum%n*10;
StringBuilder sb = new StringBuilder();
for(int i=0;i<len;sum=sum%n*10,++i){
sb.append(sum/n);
}
System.out.println(sb);
}
sc.close();
}
}