牛客练习赛43 B Tachibana Kanade Loves Probability 快速幂+模拟除法(Java版)

链接: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();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值