蓝桥杯真题_Java组别B_2018

2018-方格计数

/*
标题:方格计数

在二维平面上有无数个1x1的小方格。
我们以某个小方格的一个顶点为圆心画一个半径为1000的圆。
你能计算出这个圆里有多少个完整的小方格吗?

注意:需要提交的是一个整数,不要填写任何多余内容。
*/
//思路:将中心看作象限的中点,遍历第一象限的右上角,只要右上角处于圈内即所代表的方格处于圈内(勾股定理)

public class 方格计数 {
    public static void main(String[] args) {
        long n=0;
        for (int i = 1; i <= 1000; i++) {
            for (int j = 1; j <= 1000; j++) {
                if(i*i+j*j<=1000*1000){
                    n++;
                }
            }
        }
        System.out.println(n*4);
    }
}

这道题还是挺简单的,还有数边的的较优解,但感觉没看的必要

2018-测试次数

/*
x星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的2楼。
如果手机从第7层扔下去没摔坏,但第8层摔坏了,则手机耐摔指数=7。
特别地,如果手机从第1层扔下去就坏了,则耐摔指数=0。
如果到了塔的最高层第n层扔没摔坏,则耐摔指数=n
为了减少测试次数,从每个厂家抽样3部手机参加测试。
某次测试的塔高为1000层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?
*/

思路:
首先,最佳策略即即为是在每次运气最差时取得的最小值
手机数量(F)和层数(N)是固定的,测试次数F[i]则可分情况进行判断
F=1;N=1000:当只有一部手机时只能从下挨个进行测试 F[N]=N
F=2;N=1000:两部手机时,则可进行选择测试(先测试i层再分情况判断),
1)、如果测试后手机状态为好,那么F=2,N=1000-i(继续判断i层之上)
2)、但如果手机为坏时,手机只剩一部,这样又需要进行F=1时的情况,那这样F[N]=1+F[i]
这样的最佳策略还是有些模糊,那我们就将i的值从1开始遍历
假使F=2&&N=4时:
思维图片;t(手机数量,所测试楼层)
当状态为好时,F[N]=1+t(F,N-i)
当状态为坏时,F[N]=1+t(F-1,N-1)

也就是说当手机数量F=1时的测试次数已知,而当F++时我们总能通过已知的F[i]计算出F[i+1]的值,直到i+1=N;

这样可以设立三个数组,挨个定义其中的值只需要最后输出F3[N]的值

public class 测试次数 {//手机数与楼层数为固定值,最优策略为每种情况下运气差的值中的最小值(所有最大值中的最小值)
    static final int N = 1000;//设置常量层数
    static int[] f1 = new int[N + 1];
    static int[] f2 = new int[N + 1];
    static int[] f3 = new int[N + 1];

    public static void main(String[] args) {
        //当只有一部手机的情况
        for (int i = 1; i <= N; i++) {
            f1[i] = i;
        }
        //两部手机的情况
        for (int i = 1; i <= N; i++) {
            int ans = Integer.MAX_VALUE;
            for (int j = 1; j <= i; j++) { //不能直接通过N进行计算,内循环一步步算上去
                int _max = 1 + Math.max(f2[i - j], f1[j - 1]);//选择每层进行测试时运气差的那一次
                ans = Math.min(ans, _max);//所有差运气中的最佳策略
            }
            f2[i] = ans;
        }
        //三部手机的情况
        for (int i = 1; i <= N; i++) {
            int ans = Integer.MAX_VALUE;
            for (int j = 1; j <= i; j++) {
                int _max = 1 + Math.max(f3[i - j], f2[j - 1]);
                ans = Math.min(ans, _max);
            }
            f3[i] = ans;
        }
        System.out.println(f3[N]);
    }
}

还有一个二维数组的写法,思路也是这样的,就不重复啰嗦了

2018-螺旋曲线

问题:
如图p1.png所示的螺旋折线经过平面上所有整点恰好一次。
对于整点(X, Y),我们定义它到原点的距离dis(X, Y)是从原点到(X, Y)的螺旋折线段的长度。
例如dis(0, 1)=3, dis(-2, -1)=9
给出整点坐标(X, Y),你能计算出dis(X, Y)吗?
【输入格式】
X和Y
对于40%的数据,-1000 <= X, Y <= 1000
对于70%的数据,-100000 <= X, Y <= 100000
对于100%的数据, -1000000000 <= X, Y <= 1000000000
【输出格式】
输出dis(X, Y)
【样例输入】
0 1
【样例输出】
3

P1.png
思路:
在二四象限作一条斜线分割此折线
思路图

这样每一个右下角的折点的距离即为右上N个三角形的两边和与左下N个三角形的两边和(其中N为折点的X轴坐标),这样将两边的三角形合看作一个等差数列,进行求和,再判断每个点距离与他最近的折点的距离,进行加或减

public class 螺旋折线 {
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        long x=input.nextLong();
        long y=input.nextLong();
        long n=0;//定义圈数
        long d=0;//长度

        if(y>0&&Math.abs(x)<=y){
            n=y;
            d=y-x+2*y;
        } else if(x>0&&Math.abs(y)<=x){
            n=x;
            d=x+y;
        }else if(y<=0&&x>=y-1&&x<=-y){
            n=-y;
            d=-(-y-x);//将长度转为负数,后边负负得正
        }else if(x<0&&y>=x+1&&y<=-x){
            n=-x-1;
            d=-(y-x-1-2*x-1);
        }
        System.out.println(sum(6,n,8)-d);
        //将两个等差数列合为一个,减去d的值(左下的值为负数即加上)
    }
    public static long sum(long a0,long n,long d){//等差数列求和方法
        return (2*a0+(n-1)*d)*n/2;
    }

}

2018-复数幂

问题:
设i为虚数单位。对于任意正整数n,(2+3i)^n 的实部和虚部都是整数。
求 (2+3i)^123456 等于多少? 即(2+3i)的123456次幂,这个数字很大,要求精确表示。
答案写成 “实部±虚部i” 的形式,实部和虚部都是整数(不能用科学计数法表示),中间任何地方都不加空格,实部为正时前面不加正号。
(2+3i)^2 写成: -5+12i,
(2+3i)^5 的写成: 122-597i
注意:需要提交的是一个很庞大的复数,不要填写任何多余内容。

思路:
用循环实现幂,a代表实部,b代表虚部,因为最后的值很大,所以开始就定义为Big型。循环一次后实部=2a-(3b),虚部=3a+2b。


public class 负数幂 {
    public static void main(String[] args) throws FileNotFoundException {
        BigInteger two = BigInteger.valueOf(2);//2和3不能直接用所以定义为BigInteger型
        BigInteger three = BigInteger.valueOf(3);

        BigInteger a = BigInteger.valueOf(2);
        BigInteger b = BigInteger.valueOf(3);
        BigInteger aa = null;
        BigInteger bb = null;

        for (int i = 0; i < 123455; i++) {
            aa = a.multiply(two).subtract(b.multiply(three));//a*2-(b*3)
            bb = a.multiply(three).add(b.multiply(two));//a*3+b*2

            a = aa;//将aa的值赋予a中进行下次循环
            b = bb;
        }
        //System.setOut(new PrintStream(new File("E:\\out.txt")));//输出到文本以查看
        System.out.println(aa + (bb.compareTo(BigInteger.ZERO) < 0 ? "-" : "+") + bb + "i");
        //bb.compareTo(BigInteger.ZERO) < 0 ? "-" : "+"  判断bb是否小于0,小于输出一个负号,大于输出加号
    }
}
2018-递归三元组

题目:
给定三个整数数组
A = [A1, A2, … AN],
B = [B1, B2, … BN],
C = [C1, C2, … CN],
请你统计有多少个三元组(i, j, k) 满足:

  1. 1 <= i, j, k <= N
  2. Ai < Bj < Ck

【输入格式】
第一行包含一个整数N。
第二行包含N个整数A1, A2, … AN。
第三行包含N个整数B1, B2, … BN。
第四行包含N个整数C1, C2, … CN。

对于30%的数据,1 <= N <= 100
对于60%的数据,1 <= N <= 1000
对于100%的数据,1 <= N <= 100000 0 <= Ai, Bi, Ci <= 100000

【输出格式】
一个整数表示答案

【输入样例】
3
1 1 1
2 2 2
3 3 3

【输出样例】
27
思路:
首先将三组数自小到大进行排列,
以b组做判断,a组中比b组小的的下标为p个,c组中比b组大的的下标为n-q个
也就是说,p*(n-q)的值就是当j固定时(i,j,k)的个数
遍历b组,将每一组符合条件的p*(n-q)加起来的总和就是所有(i,j,k)的个数

public class 递归三元组 {
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        int N=input.nextInt();
        int[] a=new int[N];
        int[] b=new int[N];
        int[] c=new int[N];

        for (int i = 0; i < N; i++) {
            a[i]=input.nextInt();
        }
        for (int i = 0; i < N; i++) {
            b[i]=input.nextInt();
        }
        for (int i = 0; i < N; i++) {
            c[i]=input.nextInt();
        }

        Arrays.sort(a);
        Arrays.sort(b);
        Arrays.sort(c);

        int p=0,q=0;
        long ans=0;
        for (int i = 0; i < N; i++) {
            while (p<N&&a[p]<b[i])p++;
            while (q<N&&c[q]<=b[i])q++;
            ans+=1L*p*(N-q);//因为ans是一个长整型,所以在乘式前加上1L将其转换格式
        }
        System.out.println(ans);

    }
}

这篇帖子就到这了,以后也不更了,毕竟是为了比赛刷的题,得有针对性啊,一点数据结构的基础也没有,所以后边太难的就不研究了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值