当前位置: 首页 > news >正文

蓝桥杯java2021年十二届国赛大学A组真题答案整理

积木

题目描述

小明用积木搭了一个城堡。

为了方便,小明在搭的时候用的是一样大小的正方体积本,搭在了一个 nn 行 mm 列的方格图上,每个积木正好占据方格图的一个小方格。

当然,小明的城堡并不是平面的,而是立体的。小明可以将积木垒在别的积木上面。当一个方格上的积木垒得比较高时,就是一个高塔,当一个方格上没有积木时,就是一块平地。

小明的城堡可以用每个方格上垒的积木层数来表示。例如,下面就表示一个城堡。

9 3 3 1

3 3 3 0

0 0 0 0

这个城堡南面和东面都有空地,西北面有一个大房子,在西北角还有一个高塔,东北角有一个车库。

现在,格格巫要来破坏小明的城堡,他施了魔法水淹小明的城堡。

如果水的高度为 1,则紧贴地面的那些积木要被水淹,在上面的例子中,有 7 块积木要被水淹。

如果水的高度为 2,则更多积木要被水淹,在上面的例子中,有 13 块积木要被水淹。

给定小明的城堡图,请问,水的高度依次为 1,2,3,⋯,H1,2,3,⋯,H 时,有多少块积木要被水淹。

输入描述

输入的第一行包含两个整数 n,mn,m。

接下来 nn 行,每行 mm 个整数,表示小明的城堡中每个位置积木的层数。

接下来包含一个整数 HH,表示水高度的上限。

其中,1≤n,m≤1000,1≤H≤105,积木层数不超过1091≤n,m≤1000,1≤H≤105,积木层数不超过109。

输出描述

输出 HH 行,每行一个整数。第 ii 的整数表示水的高度为 ii时被水淹的积木数量。

分析:首先看到这个题目就应该想到哈希记录每个高度积木的数量,再看到H=1e5,明显的hash,但要注意hash记录的是高度的积木数,不是该层数的积木数,所以要定义一个sum来计算每层积木数

import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int m = in.nextInt();int[] hash = new int[(int)1e5 + 5];long sumi = 0l;long ans = 0l;for(int i = 0; i < n; i++){for(int j = 0; j < m; j++){int h = in.nextInt();if(h>0){sumi++;hash[h]++;}}}//到这里sumi即为第一层的积木数int H = in.nextInt();for(int i = 1; i <= H; i++){ans+=sumi;System.out.println(ans);sumi -= hash[i];//减去已经淹没的积木,sumi变成当前层的积木数}in.close();}
}

冰山

题目描述

一片海域上有一些冰山,第 ii 座冰山的体积为 ViVi​。

随着气温的变化,冰山的体积可能增大或缩小。第 ii 天,每座冰山的变化量都是 XiXi​。当 Xi>0Xi​>0 时,所有冰山体积增加 XiXi​;当 Xi<0Xi​<0 时,所有冰山体积减少 −Xi−Xi​;当 Xi=0Xi​=0 时,所有冰山体积不变。

如果第 ii 天某座冰山的体积变化后小于等于 00,则冰山会永远消失。

冰山有大小限制 kk。如果第 ii 天某座冰山 jj 的体积变化后 VjVj​ 大于 kk,则它会分裂成一个体积为 kk 的冰山和 Vj−kVj​−k 座体积为 11 的冰山。

第 ii 天结束前(冰山增大、缩小、消失、分裂完成后),会漂来一座体积为 YiYi​ 的冰山(Yi=0Yi​=0 表示没有冰山漂来)。 小蓝在连续的 mm 天对这片海域进行了观察,并准确记录了冰山的变化。

小蓝想知道,每天结束时所有冰山的体积之和(包括新漂来的)是多少。 由于答案可能很大,请输出答案除以 998244353998244353 的余数。

输入描述

输入的第一行包含三个整数 n,m,kn,m,k,分别表示初始时冰山的数量、观察的天数以及冰山的大小限制。

第二行包含 nn 个整数 V1,V2,⋯,VnV1​,V2​,⋯,Vn​,表示初始时每座冰山的体积。 接下来 mm 行描述观察的 mm 天的冰山变化。其中第 ii 行包含两个整数 Xi,YiXi​,Yi​,意义如前所述。

输出描述

输出 mm 行,每行包含一个整数,分别对应每天结束时所有冰山的体积之和除以 998244353998244353 的余数。

分析:hash加暴力,能通过80%的用例

import java.util.*;
import java.io.*;public class Main {static final long MOD = 998244353;public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new InputStreamReader(System.in));BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));StringTokenizer st = new StringTokenizer(br.readLine());// 读取初始冰山数量、观察天数和冰山大小限制int initialIcebergs = Integer.parseInt(st.nextToken());int daysObserved = Integer.parseInt(st.nextToken());int maxSize = Integer.parseInt(st.nextToken());// 使用HashMap记录冰山体积和对应的数量Map<Long, Long> volumeCount = new HashMap<>();// 读取初始冰山体积st = new StringTokenizer(br.readLine());for (int i = 0; i < initialIcebergs; i++) {long volume = Long.parseLong(st.nextToken());volumeCount.put(volume, volumeCount.getOrDefault(volume, 0L) + 1);}// 处理每一天的冰山变化for (int day = 0; day < daysObserved; day++) {st = new StringTokenizer(br.readLine());int change = Integer.parseInt(st.nextToken()); // 体积变化量int newIceberg = Integer.parseInt(st.nextToken()); // 新冰山体积// 创建新的临时Map来存储处理后的冰山Map<Long, Long> newVolumeCount = new HashMap<>();// 遍历当前所有冰山for (Map.Entry<Long, Long> entry : volumeCount.entrySet()) {long currentVolume = entry.getKey();long count = entry.getValue();long newVolume = currentVolume + change;// 如果冰山体积小于等于0,则消失if (newVolume <= 0) {continue;}// 如果冰山体积超过最大限制,分裂if (newVolume > maxSize) {// 分裂为1个体积为maxSize的冰山和(newVolume - maxSize)个体积为1的冰山newVolumeCount.put((long) maxSize, (newVolumeCount.getOrDefault((long) maxSize, 0L) + count) % MOD);long ones = (newVolume - maxSize) * count % MOD;newVolumeCount.put(1L, (newVolumeCount.getOrDefault(1L, 0L) + ones) % MOD);} else {// 否则,直接更新体积newVolumeCount.put(newVolume, (newVolumeCount.getOrDefault(newVolume, 0L) + count) % MOD);}}// 更新当前冰山状态volumeCount = newVolumeCount;// 如果有新冰山漂来,添加到当前冰山中if (newIceberg != 0) {volumeCount.put((long) newIceberg, (volumeCount.getOrDefault((long) newIceberg, 0L) + 1) % MOD);}// 计算当前所有冰山的体积之和long totalVolume = 0;for (Map.Entry<Long, Long> entry : volumeCount.entrySet()) {totalVolume = (totalVolume + entry.getKey() * entry.getValue()) % MOD;}// 输出当天的总体积bw.write(totalVolume + "\n");}// 关闭输入输出流bw.flush();br.close();bw.close();}
}

纯质数

题目描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

如果一个正整数只有 11 和它本身两个约数,则称为一个质数(又称素数)。

前几个质数是:2,3,5,7,11,13,17,19,23,29,31,37,⋅⋅⋅2,3,5,7,11,13,17,19,23,29,31,37,⋅⋅⋅ 。

如果一个质数的所有十进制数位都是质数,我们称它为纯质数。例如:2,3,5,7,23,372,3,5,7,23,37 都是纯质数,而 11,13,17,19,29,3111,13,17,19,29,31 不是纯质数。当然 1,4,351,4,35 也不是纯质数。

请问,在 11 到 2021060520210605 中,有多少个纯质数?

分析:就纯暴力就行,判断素数的方法一定要记住i <= Math.sqrt(n)这里是<=;

import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args) {Scanner scan = new Scanner(System.in);//在此输入您的代码...int ans = 20210605;for(int i = 1; i <= 20210605; i++){if(is_prime(i)){int x = i;while(x > 0){if(is_prime(x%10)){x/=10;}else{ans--;break;}}}else ans--;}System.out.println(1903);scan.close();}public static boolean is_prime(int n){if(n == 1) return false;for(int i = 2; i <= Math.sqrt(n); i++){if(n%i==0){return false;}}return true;}
}

完全日期

题目描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

如果一个日期中年月日的各位数字之和是完全平方数,则称为一个完全日期。

例如:20212021 年 66 月 55 日的各位数字之和为 2+0+2+1+6+5=162+0+2+1+6+5=16,而 1616 是一个完全平方数,它是 44 的平方。所以 20212021 年 66 月 55 日是一个完全日期。

例如:20212021 年 66 月 2323 日的各位数字之和为 2+0+2+1+6+2+3=162+0+2+1+6+2+3=16,是一个完全平方数。所以 20212021 年 66 月 2323 日也是一个完全日期。

请问,从 20012001 年 11 月 11 日到 20212021 年 1212 月 3131 日中,一共有多少个完全日期?

分析:同样暴力,要记住闰年的判断条件 

import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改public class Main {static int[] mons = {31,28,31,30,31,30,31,31,30,31,30,31};public static void main(String[] args) {int ans = 0;Scanner scan = new Scanner(System.in);for(int i = 2001; i <= 2021; i++){if((i%4==0 && i%100!=0) || i%400==0){mons[1] = 29;}for(int j = 1; j <= 12; j++){for(int k = 1 ; k <= mons[j-1]; k++){int sum = ret(i) + ret(j) + ret(k);if(Math.sqrt(sum)==(int)Math.sqrt(sum)){ans++;}}}mons[1]=28;}System.out.println(ans);scan.close();}public static int ret(int x){int ret = 0;while( x > 0){ret += x%10;x/=10;}return ret;}
}

最小权值

题目描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

对于一棵有根二叉树 TT,小蓝定义这棵树中结点的权值 W(T)W(T) 如下:

空子树的权值为 00。

如果一个结点 vv 有左子树 LL, 右子树 RR,分别有 C(L)C(L) 和 C(R)C(R) 个结点,则 W(v)=1+2W(L)+3W(R)+(C(L))2C(R)W(v)=1+2W(L)+3W(R)+(C(L))2C(R)

树的权值定义为树的根结点的权值。

小蓝想知道,对于一棵有 20212021 个结点的二叉树,树的权值最小可能是多少?

分析:推出dp式dp[i] = Math.min(dp[i], 1 + 2 * dp[l] + 3 * dp[r] + (long) l * l * r); 然后暴力

 

import java.util.Arrays;
// 1:无需package
// 2: 类名必须Main, 不可修改public class Main {static long[] dp = new long[2022];public static void main(String[] args) {Arrays.fill(dp, Long.MAX_VALUE);dp[0] = 0;for (int i = 1; i <= 2021; i++) {for (int j = 0; j < i; j++) {int l = j;int r = i - j - 1;dp[i] = Math.min(dp[i], 1 + 2 * dp[l] + 3 * dp[r] + (long) l * l * r);}}System.out.println(dp[2021]);}
}

覆盖

题目描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

小蓝有一个国际象棋的棋盘,棋盘的大小为 8×88×8,即由 88 行 88 列共 6464 个方格组成。棋盘上有美丽的图案,因此棋盘旋转后与原来的棋盘不一样。

小蓝有很多相同的纸片,每张纸片正好能覆盖棋盘的两个相邻方格。小蓝想用 3232 张纸片正好将棋盘完全覆盖,每张纸片都覆盖其中的两个方格。

小蓝发现,有很多种方案可以实现这样的覆盖。如果棋盘比较小,方案数相对容易计算,比如当棋盘是 2×22×2 时有两种方案,当棋盘是 4×44×4 时有 3636 种方案。但是小蓝算不出他自己的这个 8×88×8 的棋盘有多少种覆盖方案。

请帮小蓝算出对于这个 8×88×8 的棋盘总共有多少种覆盖方案。

分析:不会;横着放好所有方块后,竖着方案是唯一的,只用考虑横着的即可,实际做法:1.先可以进行简单的合法性判定,即一个状态中连续为空的个数是否为奇数,如果为奇数,则无法竖着填满,不合法

import java.util.Arrays;public class Main {static final int n = 8, m = 8;static long[][] dp = new long[9][1 << 8]; // dp[i][j]: 处理到第i列,状态为j的方案数static boolean[] st = new boolean[1 << 8]; // 标记状态是否合法public static void main(String[] args) {// 预处理所有可能的行状态,判断哪些状态是合法的for (int i = 0; i < (1 << n); i++) {st[i] = true;int cnt = 0; // 连续空位的计数for (int j = 0; j < n; j++) {if ((i >> j & 1) == 1) { // 如果当前位置被覆盖if ((cnt & 1) == 1) { // 如果连续空位是奇数个,不合法st[i] = false;break;}cnt = 0;} else {cnt++;}}if ((cnt & 1) == 1) { // 检查最后的连续空位st[i] = false;}}// 初始化动态规划表for (int i = 0; i < 9; i++) {Arrays.fill(dp[i], 0);}dp[0][0] = 1; // 初始状态:第0列全空,方案数为1// 动态规划转移for (int i = 1; i <= m; i++) { // 遍历每一列for (int j = 0; j < (1 << n); j++) { // 当前列的状态for (int k = 0; k < (1 << n); k++) { // 前一列的状态if ((j & k) == 0 && st[j | k]) { // 状态组合合法dp[i][j] += dp[i - 1][k];}}}}System.out.println(dp[m][0]); // 输出完全覆盖的方案数}
}

 123

题目描述

小蓝发现了一个有趣的数列,这个数列的前几项如下:

1,1,2,1,2,3,1,2,3,4,⋯1,1,2,1,2,3,1,2,3,4,⋯

小蓝发现,这个数列前 11 项是整数 11,接下来 22 项是整数 11 至 22,接下来 33 项是整数 11 至 33,接下来 44 项是整数 11 至 4,依次类推。

小蓝想知道,这个数列中,连续一段的和是多少。

输入描述

输入的第一行包含一个整数 TT,表示询问的个数。

接下来 TT 行,每行包含一组询问,其中第 ii 行包含两个整数 lili​ 和 riri​,表示询问数列中第 lili​ 个数到第 riri​ 个数的和。

输出描述

输出 TT 行,每行包含一个整数表示对应询问的答案。

分析:前缀和加二分查找,二分查找这里要注意终止条件

import java.util.Scanner;public class Main {static int maxLen = 1414215; // 预估足够大的段数static long[] a = new long[maxLen]; // a[i]:前i段的总数字个数static long[] s = new long[maxLen]; // s[i]:前i段所有数字的总和public static void main(String[] args) {Scanner scan = new Scanner(System.in);// 预处理a和s数组a[0] = 0;for (int i = 1; i < maxLen; i++) {a[i] = a[i - 1] + i; // 第i段有i个数字}s[0] = 0;for (int i = 1; i < maxLen; i++) {s[i] = s[i - 1] + a[i]; // 第i段的和刚好是a[i] = 1 + 2 + 3...+i}int T = scan.nextInt(); // 查询次数for (int i = 0; i < T; i++) {long l = scan.nextLong();long r = scan.nextLong();System.out.println(preSum(r) - preSum(l - 1)); // 输出区间和}scan.close();}// 计算前num个数的和private static long preSum(long num) {if (num == 0) return 0;int l = 0, r = maxLen - 1;while (l <= r) {int mid = (l + r ) / 2;if (a[mid] <= num) {l = mid + 1;} else {r = mid - 1;}}return s[l-1] + a[(int) (num - a[l-1])];}
}

二进制问题

题目描述

小蓝最近在学习二进制。他想知道 11 到 NN 中有多少个数满足其二进制表示中恰好有 KK 个 11。你能帮助他吗?

输入描述

输入一行包含两个整数 NN 和 KK。

输出描述

输出一个整数表示答案。

分析:记忆化搜索加动态规划,原本以为是简单的排列组合,结果只过了两个样例,发现N会限制每一位上的数,比如N=10,就是1010,那么你就不能出现1100的组合,就相当于你第一位选了1就会限制后面的数,第一位选了0就不会限制,因为少一位肯定不会比N大


// 1:无需package
// 2: 类名必须Main, 不可修改// public class Main {
//     public static void main(String[] args) {
//         Scanner scan = new Scanner(System.in);
//         int n = scan.nextInt();
//         int k = scan.nextInt();
//         int count = 0;
//         while (n != 0) {
//             count++;
//             n >>= 1; // 右移一位
//         }
//         if(count<k){
//           System.out.println(0);
//           return;
//         }
//         System.out.println(C(count,k));
//         scan.close();
//     }
//     public static long C(int n, int k){
//       long ret = 1;
//       for(int i = 0; i < k; i++){
//           ret*=n;
//           n--;
//       }
//       return ret;
//     }
// }
import java.util.Scanner;public class Main {static Long[][][] memo; // 记忆化数组static int[] bin;       // N的二进制数组static int len;         // 数组长度static int K;public static void main(String[] args) {Scanner sc = new Scanner(System.in);long N = sc.nextLong();K = sc.nextInt();String s = Long.toBinaryString(N);len = s.length();bin = new int[len];for (int i = 0; i < len; i++) {bin[i] = s.charAt(i) - '0';}// 如果K大于二进制位数,直接返回0if (K > len) {System.out.println(0);sc.close();return;}// 初始化记忆化数组:位置、已选1个数(最多K个)、是否受限制memo = new Long[len][K + 1][2];long result = dfs(0, 0, 1);System.out.println(result);sc.close();}/*** @param pos 当前处理的二进制位(从0开始,0是最高位)* @param countOne 已经选择的1的个数* @param limit 是否受到上界限制(1表示还不能超过原N对应位,0表示已不限)* @return 满足条件的方案数*/static long dfs(int pos, int countOne, int limit) {if (countOne > K) {return 0; // 已经超过K个1,后续无需处理}if (pos == len) {// 全部位都处理完,判断是否恰好有K个1return countOne == K ? 1 : 0;}if (memo[pos][countOne][limit] != null) {return memo[pos][countOne][limit];}long res = 0;int up = limit == 1 ? bin[pos] : 1; // 当前可以选的最大数字(0或1)for (int dig = 0; dig <= up; dig++) {int newLimit = (limit == 1 && dig == up) ? 1 : 0;res += dfs(pos + 1, countOne + (dig == 1 ? 1 : 0), newLimit);}memo[pos][countOne][limit] = res;return res;}
}

异或三角

题目描述

给定 TT 个数 n1,n2,⋯,nTn1​,n2​,⋯,nT​,对每个 nini​ 请求出有多少组 aa, bb, cc 满足:

  1. 1≤a,b,c≤ni1≤a,b,c≤ni​;
  2. a⊕b⊕c=0a⊕b⊕c=0,其中 ⊕⊕ 表示二进制按位异或;
  3. 长度为 a,b,ca,b,c 的三条边能组成一个三角形。

输入描述

输入的第一行包含一个整数 TT。

接下来 TT 行每行一个整数,分别表示 n1,n2,⋯,nTn1​,n2​,⋯,nT​。

输出描述

输出 TT 行,每行包含一个整数,表示对应的答案。

分析:暴力失败,看题解数位dp,完全不懂

import java.util.Arrays;
import java.util.Scanner;public class XORTriangle {private static int[] num = new int[32]; // 存储n的二进制表示private static long[][][] dp = new long[32][2][8]; // DP记忆化数组public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int t = scanner.nextInt();while (t-- > 0) {int n = scanner.nextInt();System.out.println(calculate(n));}}private static long calculate(int n) {// 初始化DP数组for (int i = 0; i < 32; i++) {for (int j = 0; j < 2; j++) {Arrays.fill(dp[i][j], -1);}}// 将n分解为二进制int bitCount = 0;while (n != 0) {num[++bitCount] = n & 1;n >>= 1;}// 三种情况:a、b、c分别作为最大边return dfs(bitCount, 1, 0) * 3;}private static long dfs(int bitPos, int limit, int state) {if (bitPos == 0) {return state == 7 ? 1 : 0; // 必须所有组合都出现过}if (dp[bitPos][limit][state] != -1) {return dp[bitPos][limit][state];}long res = 0;int upperBound = (limit == 1) ? num[bitPos] : 1;for (int aBit = 0; aBit <= upperBound; aBit++) {if (aBit == 0) {// a当前位取0res += dfs(bitPos - 1, limit & (aBit == upperBound ? 1 : 0), state); // b取0if (state >= 6) { // 确保(1,1)和(1,0)已出现res += dfs(bitPos - 1, limit & (aBit == upperBound ? 1 : 0), state | 1); // b取1}} else {// a当前位取1res += dfs(bitPos - 1, limit & (aBit == upperBound ? 1 : 0), state | 2); // b取0res += dfs(bitPos - 1, limit & (aBit == upperBound ? 1 : 0), state | 4); // b取1}}return dp[bitPos][limit][state] = res;}
}

坚持暴力,能过两个样例(

import java.util.Scanner;public class ImprovedBruteForce {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int T = sc.nextInt();for (int t = 0; t < T; t++) {int n = sc.nextInt();long count = 0;for (int a = 1; a <= n; a++) {for (int b = 1; b <= n; b++) {int c = a ^ b;// 只考虑范围内的if (c >= 1 && c <= n) {// 判断三角形条件if (a + b > c && a + c > b && b + c > a) {count++;}}}}System.out.println(count);}sc.close();}
}

和与乘积

题目描述

给定一个数列 A=(a1,a2,⋯,an)A=(a1​,a2​,⋯,an​),问有多少个区间 [L,R][L,R] 满足区间内元素的乘积等于他们的和,即 aL⋅aL+1⋯aR=aL+aL+1+⋯+aRaL​⋅aL+1​⋯aR​=aL​+aL+1​+⋯+aR​ 。

输入描述

输入第一行包含一个整数 nn,表示数列的长度。

第二行包含 nn 个整数,依次表示数列中的数 a1,a2,⋯,ana1​,a2​,⋯,an​。

输出描述

输出仅一行,包含一个整数表示满足如上条件的区间的个数。

分析:暴力可以过70%的样例

import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int[] A = new int[n];for (int i = 0; i < n; i++) {A[i] = sc.nextInt();}long count = 0;int left = 0;while (left < n) {long product = 1L;long sum = 0L;for (int right = left; right < n; right++) {product *= A[right];sum += A[right];if (product == sum) {count++;}}left++;}System.out.println(count);}
}

优化后可以过100%

import java.io.IOException;
import java.util.Arrays;
import java.util.Scanner;public class Main {public static void main(String[] args) throws IOException {// 创建Scanner对象读取输入Scanner sc = new Scanner(System.in);// 读取数字序列的长度nint n = sc.nextInt();// data数组存储原始数据,索引1到nlong data[] = new long[n+1];// map数组存储前缀和,map[i]表示前i个元素的和long map[] = new long[n+1];// no1数组存储所有非1元素的索引位置int no1[] = new int[n+1];// bigIndex记录非1元素的数量int bigIndex = 0;// 读取数据并预处理for(int i = 1; i <= n; ++i) {data[i] = sc.nextInt();  // 读取第i个数字map[i] = map[i-1] + data[i];  // 计算前缀和// 如果当前数字不是1,记录其位置if(data[i] != 1) {no1[++bigIndex] = i;  // no1数组从1开始存储非1元素的位置}}// dif数组:dif[i]表示第i个元素后面连续1的个数long dif[] = new long[n+1];// x记录当前连续1的个数for(int i = n, x = 0; i >= 1; --i) {dif[i] = x;  // 记录当前位置后面连续1的个数// 更新x的值if(data[i] != 1) {x = 0;  // 遇到非1元素,重置计数器} else {++x;    // 遇到1,计数器加1}}// ans记录满足条件的子序列数量(不包括长度为1的)long ans = 0;// 遍历所有可能的子序列起始位置lfor(int l = 1; l <= n; ++l) {long now = data[l];  // now记录当前子序列的乘积,初始为data[l]// 使用二分查找在no1数组中找到第一个大于等于l的位置// Arrays.binarySearch返回:// - 如果找到,返回索引(>=0)// - 如果没找到,返回(-插入点-1)int rr = Arrays.binarySearch(no1, 1, bigIndex+1, l);// 处理二分查找结果rr = rr >= 0 ? rr + 1 : -rr - 1;  // 转换为no1数组中第一个大于l的元素索引// 遍历所有可能的结束位置r(非1元素)for(int x = rr; x <= bigIndex; ++x) {int r = no1[x];  // 获取非1元素的位置// 如果当前子序列包含多个元素,更新乘积if(r != l) {now *= data[r];}// 提前终止条件:如果乘积已经超过整个数组的和,后续乘积只会更大if(now > map[n]) {break;}// 计算子序列[l..r]的和(使用前缀和数组快速计算)long sum = map[r] - map[l-1];/* 关键判断条件:* 1. 乘积 >= 原始和(不含后面连续1的和)* 2. 乘积 <= 原始和 + 后面连续1的个数(因为每个1会使和增加1)* * 这意味着我们可以通过在子序列后面添加k个连续1(0 <= k <= dif[r])* 来使和等于乘积*/if(now >= sum && now <= sum + dif[r]) {++ans;  // 满足条件,计数器加1}}}// 最终结果:长度为1的子序列有n个(都满足条件)// 加上其他满足条件的子序列数量ansSystem.out.println(n + ans);}
}

 

相关文章:

  • 如何手搓扫雷(待扩展)
  • [SC]SystemC在CPU/GPU验证中的应用(四)
  • JSR 303(即 Bean Validation)是一个通过​​注解在 Java Bean 上定义和执行验证规则​​的规范
  • C++ 的四种强制类型转换:static_cast、dynamic_cast、const_cast 和 reinterpret_cast
  • LXQt修改开始菜单高亮
  • NW969NW978美光闪存颗粒NW980NW984
  • python连接邮箱的协议选择
  • fork函数小解
  • 学习笔记:3个学习AI路上反复看到的概念:RAG,Langchain,Agent
  • 二叉搜索树——红黑树
  • 投稿Cover Letter怎么写
  • 简单cnn
  • Deepin 20.9社区版安装Docker
  • c++第四课(基础c)——布尔变量
  • 深入Java性能调优:原理详解与实战
  • Linux基本指令/下
  • 【判断数字递增】2021-12-19
  • 第二章支线三 ·《CSS炼金术:动画与变换高级奥义》
  • 《重新定义高效微调:QLoRA 4位量化的颠覆式创新解析》
  • WIFI中2.4G和5G的区别,和WiFi5,WiFi6和WiFi7的区别,
  • 做兼职在什么网站找比较好/关键词推广优化外包
  • 网站总体结构/培训行业seo整站优化
  • 商务网站的建设与管理/seo分析工具有哪些
  • redis连接wordpress/广州新塘网站seo优化
  • 网站怎么建设的/网络营销推广方案论文
  • 福州做网站互联网公司排名/武汉seo论坛