2018年第九届蓝桥杯省赛Java B组真题+个人题解

目录

一、第几天

二、方格计数

四、测试次数

六、递增三元组

七、螺旋折线

八、日志统计

九、全球变暖

十、堆的计数


一、第几天

蓝桥杯官网_第几天

 思路:

利用Java中LocalDate类求解

答案:

125

代码:

import java.io.IOException;
import java.io.PrintWriter;
import java.time.LocalDate;

public class Main {
    static PrintWriter pw=new PrintWriter(System.out);
    public static void main(String args[]) throws IOException{
        LocalDate d1= LocalDate.of(2000,1,1);
        LocalDate d2=LocalDate.of(2000,5,4);
        int res=1;
        while (!d1.equals(d2)){
            res++;
            d1=d1.plusDays(1);
        }
        pw.println(res);
        pw.close();
    }
}

二、方格计数

蓝桥杯官网_方格计数

 思路:

思路:

将图按上述形式建立坐标系,每个小方格用其右上方顶点代替
由于四个象限对称,因此只需要求第一象限内有多少个点与圆心的距离<=半径,再乘以4即是最终结果

 答案:

7853781044

代码:

import java.io.IOException;
import java.io.PrintWriter;

public class Main {
    static PrintWriter pw=new PrintWriter(System.out);
    public static void main(String args[]) throws IOException{
//        long res=0;
//        for(long i=1;i<=50000;i++){
//            for(long j=1;j<=50000;j++){
//                if(i*i+j*j<=(long)Math.pow(50000,2)){
//                    res++;
//                }
//            }
//        }
//        pw.println(res*4);
        pw.println(7853781044l);
        pw.close();
    }
}

四、测试次数

蓝桥杯官网_测试次数

 思路:

本题要理解最坏运气和最佳策略
最坏运气是指在每一楼层扔均有好坏两种结果,从而有不同的测试次数, 选其中的较大者,是同一层的比较。
最佳策略是指从不同楼层开始扔有不同的测试次数,在最坏运气的前提下, 选择其中的较小者,是不同楼层之间的比较
f(i,j)表示有i部手机,最高有j层楼所需要的测试次数, k代表从哪一层开始扔,按照第k层扔手机的好坏具有一下公式,每层都取其中较大者,即是最坏运气;不同层的最大值中的最小值即是最佳策略。
最终答案即是f(3,1000)

 f(2,3)计算过程:选择三种的最小值,因此f(2,3)=2

  f(2,4)计算过程:选择四种的最小值,因此f(2,4)=3

 答案:

19

代码:

import java.io.IOException;
import java.io.PrintWriter;

public class Main{
    static PrintWriter pw=new PrintWriter(System.out);
    static int f[][]=new int[5][1010];//f[i][j]表示有i部手机,测试塔高为j的测试次数
    public static void main(String args[]) throws IOException{
        for(int i=1;i<=1000;i++){
            f[1][i]=i;//只有1部手机,只能从低层开始扔,最坏运气即是每次扔都是好的,有多少层就要扔多少次
        }
        for(int i=2;i<=3;i++){//手机个数
            f[i][1]=1;//只有一层时,只需要扔一次
            for(int j=2;j<=1000;j++){//测试层数
                int res=(int)2e9;
                for(int k=1;k<=j;k++){//从第几层开始扔
                    int x= Math.max(1+f[i-1][k-1],1+f[i][j-k]);//最坏运气
                    res= Math.min(res,x);//最佳策略
                }
                f[i][j]=res;
            }
        }
        pw.println(f[3][1000]);
        pw.close();
    }
}

六、递增三元组

蓝桥杯官网_递增三元组

 思路:

遍历B数组,每次计算A中有多少数组比它小,记为res1,C中有多少数组比它大,记为res2,则共有res1*res2种情况,最后将每种情况相加即是最终答案
利用二分查找个数,总的时间复杂度为0(nlogn)

代码:

import java.io.*;
import java.util.Arrays;

public class Main {
    static StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter pw=new PrintWriter(System.out);
    public static int nextInt() throws IOException{
        st.nextToken();
        return (int)st.nval;
    }
    static int n;
    static int N=100010;
    static int a[]=new int[N];
    static int b[]=new int[N];
    static int c[]=new int[N];
    public static void main(String args[]) throws IOException{
        n=nextInt();
        for(int i=1;i<=n;i++) a[i]=nextInt();
        for(int i=1;i<=n;i++) b[i]=nextInt();
        for(int i=1;i<=n;i++) c[i]=nextInt();
        Arrays.sort(a,1,n+1);//排序,利用二分查找答案
        Arrays.sort(c,1,n+1);
        long res=0;
        for(int i=1;i<=n;i++){
            long res1=0,res2=0;
            if(a[1]>=b[i]) res1=0;//a的最小值还没bi大,说明a中没有数字比它小
            else{//二分找到最后一个比bi小的下标
                int l=1,r=n;
                while (l<r){
                    int mid=l+r+1>>1;
                    if(a[mid]<b[i]) l=mid;
                    else r=mid-1;
                }
                res1=r;
            }
            if(c[n]<=b[i]) res2=0;//c的最大值还没bi大,说明c中没有数字比它大
            else{//二分找到第一个比bi大的下标
                int l=1,r=n;
                while (l<r){
                    int mid=l+r>>1;
                    if(c[mid]>b[i]) r=mid;
                    else l=mid+1;
                }
                res2=n-r+1;
            }
            res+=res1*res2;
        }
        pw.println(res);
        pw.close();
    }
}

七、螺旋折线

蓝桥杯官网_螺旋折线

 思路

将如图所示的边平移至箭头所指位置,则图就变为一个一个的正方形,将正方形从1开始进行编号,发现每个点的横纵坐标绝对值的较大值代表其在第几个正方形上,例如(-3,2)即在第三个正方形上
由于正方形的边长是一个等差数列,假设该点在第n个正方形上,其边长为2n,则其内部正方形的总边长为(2+4+6+8+···2n)*4=4*n*(n-1),每个正方形的起点为(-n,-n),因此再加上(-n,-n)到(x,y)的距离即可,按照在y=x上方还是下方分情况讨论,具体详见注释

 代码:

import java.io.*;

public class Main {
    static StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter pw=new PrintWriter(System.out);
    public static int nextInt() throws IOException{
        st.nextToken();
        return (int)st.nval;
    }
    static int x,y;
    static long res=0;
    public static void main(String args[]) throws IOException{
        x=nextInt();
        y=nextInt();
        int n= Math.max(Math.abs(x), Math.abs(y));//在第n个正方形上
        res=4l*n*(n-1);//前n-1个正方形之和
        int x1=x+n,y1=y+n;//(-n,-n)到(x,y)的横向和纵向距离
        if(y>=x) res+=x1+y1;//在y=x上方,直接加上横向和纵向距离
        else res+=8l*n-x1-y1;//在y=x下方,所在正方形的总边长为2n*4,减去横向和纵向距离
        pw.println(res);
        pw.close();
    }
}

八、日志统计

蓝桥杯官网_日志统计

 思路:

创建node类存储每条记录,利用双指针算法计算在[t,t+d)区间内点赞数,判断其是否为热帖

代码:

import java.io.*;
import java.util.Arrays;

public class Main {
    static StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter pw=new PrintWriter(System.out);
    public static int nextInt() throws IOException{
        st.nextToken();
        return (int)st.nval;
    }
    static class node implements Comparable<node>{
        int ts,id;
        public node(int ts,int id){
            this.ts=ts;
            this.id=id;
        }
        public int compareTo(node p){
            return Integer.compare(ts,p.ts);
        }
    }
    static int n,d,k;
    static int N=100010;
    static node p[]=new node[N];
    static boolean flag[]=new boolean[N];
    static int cnt[]=new int[N];
    public static void main(String args[]) throws IOException{
        n=nextInt();
        d=nextInt();
        k=nextInt();
        for(int i=0;i<n;i++){
            int ts=nextInt();
            int id=nextInt();
            p[i]=new node(ts,id);
        }
        Arrays.sort(p,0,n);
        for(int i=0,j=0;i<n;i++){
            int id=p[i].id;
            while (p[i].ts-p[j].ts>=d){
                cnt[p[j].id]--;
                j++;
            }
            cnt[id]++;
            if(cnt[id]>=k) flag[id]=true;
        }
        for(int i=0;i<N;i++){
            if(flag[i]) pw.println(i);
        }
        pw.close();
    }
}

九、全球变暖

蓝桥杯官网_全球变暖

 思路:

bfs遍历每个连通块,同时记录该连通块内的陆地个数和边界个数,若相等,等代表这个连通块将会被淹没

 代码:

import java.io.*;
import java.util.LinkedList;
import java.util.Queue;

public class Main {
    static BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
    static PrintWriter pw=new PrintWriter(System.out);
    static class node{
        int x,y;
        public node(int x,int y){
            this.x=x;
            this.y=y;
        }
    }
    static int n;
    static int N=1010;
    static char g[][]=new char[N][N];
    static boolean flag[][]=new boolean[N][N];
    static int dx[]={1,-1,0,0};
    static int dy[]={0,0,1,-1};
    public static boolean bfs(node start){//start所在陆地连通块是否能被完全淹没
        Queue<node>queue=new LinkedList<>();
        queue.add(start);
        flag[start.x][start.y]=true;
        int cnt=1,bound=0;//陆地个数,边界靠海个数
        while (!queue.isEmpty()){
            node t=queue.poll();
            boolean is_bound=false;//是否边界靠海
            for(int i=0;i<4;i++){
                int x=t.x+dx[i];
                int y=t.y+dy[i];
                if(x>=0 && x<n && y>=0 && y<n && !flag[x][y]){
                    if(g[x][y]=='.'){
                        is_bound=true;
                    }
                    else if(g[x][y]=='#'){
                        cnt++;
                        flag[x][y]=true;
                        queue.add(new node(x,y));
                    }
                }
            }
            if(is_bound) bound++;
        }
        return cnt==bound;//若边界个数与陆地个数相等,则说明该陆地连通区域会被完全淹没
    }
    public static void main(String args[]) throws IOException{
        n=Integer.parseInt(bf.readLine());
        for(int i=0;i<n;i++){
            g[i]=bf.readLine().toCharArray();
        }
        int res=0;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if(!flag[i][j] && g[i][j]=='#'){
                    node start=new node(i,j);
                    if(bfs(start)) res++;
                }
            }
        }
        pw.println(res);
        pw.close();
    }
}

十、堆的计数

蓝桥杯官网_堆的计数

 

 思路:

 代码:

import java.io.*;

public class Main {
    static StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter pw=new PrintWriter(System.out);
    public static int nextInt() throws IOException{
        st.nextToken();
        return (int)st.nval;
    }
    static int n;
    static int N=100010;
    static int s[]=new int[N];//s[i]表示以i为根的子树中的节点个数
    static long f[]=new long[N];//f[i]表示以i为根的子树是小根堆的方案数,因此答案为f[1];
    static long fact[]=new long[N];//求每个数的阶乘
    static long infact[]=new long[N];//求每个数阶乘的逆元
    static int mod=1000000009;
    public static void init(){
        fact[0]=infact[0]=1;
        for(int i=1;i<N;i++){
            fact[i]=fact[i-1]*i%mod;
            infact[i]=infact[i-1]*qmi(i,mod-2,mod)%mod;
        }
    }
    public static long qmi(long a,int k,int p){
        long res=1;
        while (k!=0){
            if((k&1)==1) res=res*a%p;
            k>>=1;
            a=a*a%p;
        }
        return res;
    }
    public static long C(int a,int b){
        return fact[a]*infact[b]%mod*infact[a-b]%mod;
    }
    public static int dfs(int u){//返回以u为根节点的树的节点个数
        s[u]=1;//自身
        int l=u<<1,r=u<<1|1;
        if(l>n) return s[u];//没有左儿子,肯定没有右儿子,说明是叶子节点
        if(l<=n) s[u]+=dfs(u<<1);
        if(r<=n) s[u]+=dfs(u<<1|1);
        return s[u];
    }
    public static void main(String args[]) throws IOException{
        init();
        n=nextInt();
        dfs(1);//得到s数组
        for(int i=n/2+1;i<=n;i++) f[i]=1;//第一个叶子节点的下标为n/2+1,初始化叶子节点,方案数为1
        for(int i=n/2;i>=1;i--){//n/2为最后一个非叶子节点
            int l=i<<1,r=i<<1|1;
            f[i]=C(s[i]-1,s[l]);
            f[i]=f[l]*f[i]%mod;
            if(r<=n) f[i]=f[i]*f[r]%mod;//非叶子节点一定有左儿子,不一定有右儿子,因此需要加判断
        }
        pw.println(f[1]);
        pw.close();
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值