十四届蓝桥杯国赛JavaB组部分题解

备战蓝桥杯期间的题解,如有错误的地方,欢迎指正。

求质

题目链接:互质

问题描述
请计算在 [1,20232023] 范围内有多少个整数与2023 互质。由于结果可能很大,你只需要输出对 109+7取模后的结果


答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

互质:如果两个或两个以上的整数的最大公约数是1,则称它们为互质

2023的因数有 [7,17,119,289],而119=7 * 17,289=17 * 17,所以只需要在20232023 中将7的倍数和17的倍数减去即可求出互质的个数。
7的倍数的个数:20232023/ 7
17的倍数的个数:20232023/ 17
7和17的共同倍数的个数(重复项):20232023/ (7 * 17)
所以互质个数 = 20232023 - (20232023/ 7 + 20232023/ 17 - 20232023/(7 * 17))

模运算规则、公式与基本四则运算类似,但是除法例外。其规则如下:

(a+b)%p=(a%p+b%p)%p
(a-b)%p=(a%p-b%p)%p
(a*b)%p=(a%p * b%p)%p
ab%p=((a%p)b)%p

根据模运算分配律得 互质个数%mod = 20232023 %mod - ((20232023/ 7)%mod + (20232023/ 17)%mod - (20232023/(7*17))%mod)%mod

令 a = 20232023 b = 7,则(20232023/ 7)%mod= (a/b)%mod。根据费马小定理和欧拉定理,如果b与mod互质,则 bmod-1 %mod = 1。
又 a/b = a * b-1,所以 (a/b) % mod = (a * b-1 * b(mod-1) %mod)%mod = (a %mod * b(mod-2)%mod)%mod。同理可以求出17倍数的个数和7和17的共倍数的个数。
代码

import java.util.*;

public class Main {
    static int mod = (int)1e9+7;
    public static void main(String[] args) {
      long sum = qPow(2023,2023);
      long ans = sum;
      ans = (ans - sum * qPow(7,mod-2) + mod)%mod;
      ans = (ans - sum * qPow(17,mod-2) + mod) % mod;
      ans = (ans + sum * qPow(7*17,mod-2)) %mod;
      System.out.println(ans);
    }
    public static long qPow(long a,long b){ // 快速求幂
        long res =1;
        a %= mod;
        while(b > 0){
            if ((b&1)==1){
                res = res * a % mod;
            }
            a = a * a %mod;
            b>>=1;
        }
        return res;
    }
}

逆元

题目链接:逆元

问题描述
数论中的逆元是一个可以把除法转换为乘法的工具。若自然数 𝑎,Ia满足a × Ia ≡ 1(mod M),则称 a 在模M的意义下的逆元为Ia,这样在模M下计算除法时,可以把处以a的运算转化为乘以其逆元Ia


给定质数模数 M = 2146516019,根据费马小定理对于不是M倍数的正整数a,有a(M-1) ≡ 1(mod M),求出 [1,233333333]内所有自然数的逆元。则所有逆元的异或和为多少?


答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

题目让求出[1,233333333]中的逆元。题目给出a(M-1) ≡ 1(mod M),a × Ia ≡ 1(mod M)
即 a(M-1) = a × Ia, 逆元Ia = a(M-2)
最后将[1,233333333]中的每个数进行逆元运算异或求和
代码

import java.util.*;

public class Main {
    static int mod = 2146516019;
    public static void main(String[] args) {
        long res = qPow(1,mod-2);
        for (int i = 2; i <= 233333333; i++) {
            res ^= qPow(i,mod-2);
        }
        System.out.println(res);
    }
    public static long qPow(long a, long b) {
        long res = 1;
        a %= mod;
        while(b > 0){
            if((b&1)==1) {
                res = res * a % mod;
            }
            a = a * a % mod;
            b >>=1;
        }
        return res;
    }
}

玩具

题目链接:玩具

问题描述
小明的妈妈给他买了n个玩具,但是为了同时考察他的智力,只给了他2 × n 个零件,第i个零件的重量为wi(1 <= i <= 2 × n)。


其中任意两个零件都可以拼接成一个玩具,这个玩具的权重就等于拼接所用的两个零件的重量的乘积。小明的妈妈希望小明能够使用这2 × n 个零件拼接出 n 个玩具(每个零件必须使用且只能用一次),使得所有玩具的权重的和最小。小明希望你帮帮他计算出最小的权重和。


输入描述
输入共2行
第一行为一个正整数 n
第二行为 2 × n 个空格隔开的整数 w1 ,w2,… w2×b,


输出描述
输出共1行,一个整数。

数据量很大,枚举不现实。用贪心的思想,模拟一些数据简单测试一下,发现最小值×最大值的时候和最小。
注意用long数组,有些数据很大
代码

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        long[] arr = new long[scan.nextInt()*2];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = scan.nextInt();
        }
        Arrays.sort(arr);
        long res = 0;
        for (int i = 0; i < arr.length/2; i++) {
            res += arr[i] * arr[arr.length-i-1];
        }
        System.out.println(res);
    }
}

不完整的算式

题目链接:不完整的算式

问题描述
小蓝在黑板上写了一个形如 A op B = C 的算式,其中A、B、C都是非负整数,op是 +、-、、/(整除)四种运算之一。不过A、op、B、C这四部份有一部分被不小心的同学擦掉了。


给出这个不完整的算式,其中被擦掉的部分(被擦掉的部分是被完整的擦掉,不会出现留下若干位数字的情况)用?代替。请你输出被擦掉的部分。


输入描述
输入只有一行,包含一个字符串代表如上文所述的不完整的算式。


输出描述
如果被擦掉的部分是A、B、C之一,请输出一个整数代表答案。如果被擦掉的部分是op,请输出+、-、
、/,四个字符之一代表答案。

这道题的思路是模拟。
这道题的难点是从字符串中确定A、op、B、C的位置。其实没有很难,只是比较繁琐。
首先定义四个变量as、op、bs、cs,遍历字符串,为as、op、bs、cs赋值,并且需要记录一下 “ ?” 出现的位置。
如果把求A和求B的代码合并的话,需要特别注意“/”运算。
代码

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String s = scan.next();
        String as = "",ops="",bs="",cs="";
        int flag = 0; //   求哪个数
        // 找a
        int i = 0;
        // 第一个数
        while(s.charAt(i) - '0' >= 0 && s.charAt(i)-'0' <= 9) {
            i++;
        }
        if ( i == 0) {
            i = 1;
            flag = 1;
        }
        as = s.substring(0,i);
        // 运算符
        if (s.charAt(i) == '?'){
            flag = 2;
        }
        ops = s.substring(i,i+1);
        i++;
        int l = i;
        // 第二个数
        while(s.charAt(i) - '0' >= 0 && s.charAt(i)-'0' <= 9) {
            i++;
        }
        if (s.charAt(i) == '?'){

            flag = 3;
            i++;
        }
        bs = s.substring(l,i);
        // 跳过 = 号
        i++;
        cs = s.substring(i);
        if (cs.equals("?")){
            flag = 4;
        }
        Long a,b,c;
        if (flag == 1 || flag == 3){
            if (flag == 1) {
                b = Long.valueOf(bs);
            }else {
                b = Long.valueOf(as);
            }

             c = Long.valueOf(cs);
             switch (ops){
                 case "+":
                     System.out.println(c-b);
                     break;
                 case "-":
                     System.out.println(c+b);
                     break;
                 case "*":
                     System.out.println(c/b);
                     break;
                 case "/":
                     if (flag == 1) {
                         System.out.println(c*b);
                     }else {
                         System.out.println(b/c);
                     }

                     break;
             }
        }
        if (flag == 2) {
            a = Long.valueOf(as);
            b = Long.valueOf(bs);
            c = Long.valueOf(cs);
            if (a + b == c) {
                System.out.println("+");
            }else if (a - b == c){
                System.out.println("-");
            }else if (a * b == c) {
                System.out.println("*");
            }else if (a / b == c) {
                System.out.println("/");
            }
        }
        if (flag == 4) {
            b = Long.valueOf(bs);
            a = Long.valueOf(as);
            switch (ops){
                case "+":
                    System.out.println(a+b);
                    break;
                case "-":
                    System.out.println(a-b);
                    break;
                case "*":
                    System.out.println(a*b);
                    break;
                case "/":
                    System.out.println(a/b);
                    break;
            }
        }
    }
}

ps:没有后面是因为菜

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值