蓝桥杯历届真题蓝桥杯历届真题
蓝桥杯评测平台蓝桥杯模拟考试
题目中数据很大,这并不重要,找到解法后100和100万并无本质区别。
首先,如果只有一种2x2规格的正方形,那么平方数个小正方形正好可以拼出一个大正方形,例如4个拼出4x4,9个拼出6x6。
其次,四个1x1规格的正方形可以拼出一个2x2规格的正方形。
结合以上两点,先计算1x1规格的正方形可以拼出多少个2x2规格的正方形,再计算所有2x2规格的正方形可以拼出边长为几的大正方形。
5435122
遍历,计算每个数是否满足条件,但是结算过程中产生的数据太大,没法处理。
通过数学推导逐步简化问题。
由 (A(i) - B(i)) % 100 == 0
得 A(i) % 100 - B(i) % 100 == 0
,即 A(i) % 100 == B(i) % 100
当 i 大于等于10时, B(i) % 100 恒等于0,因为总有因子2,5,10。
则 i 大于等于10时, A(i) % 100 等于0时满足题意,
又 A(i) = (i * (i + 1)) / 2
,则应有 ( i * (i + 1) ) % 200 == 0
。
综上,解题步骤应为:
第一步,结合取余运算结果的周期性,确定 i 从1到200之间满足上式的数有几个;
第二步,确定题目中的范围中有几个整周期;
第三步,确定不足一个周期的部分满足题意的数有几个;
第四步,确定 i 小于10的部分满足题意的数有几个。
40480826628086
( a + b ) % c == ( a % c + b % c ) % c
( a - b ) % c == ( a % c - b % c ) % c
( a * b ) % c == ( a % c * b % c ) % c
首先尝试了通过数学方式分解,结果没什么思路。上网搜了下题解,发现大都是通过找规律解决问题。已知2、4、8都不具有诗意,它们都是2的次幂,验证后发现16、32也不具有诗意,那么就可以将问题转换为判断一个数字是否为2的次幂。
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int cnt = 0;
long a = 0L;
for(int i = 0; i < n; i++){
a = sc.nextLong();
if( ( a & (a - 1) ) == 0){
cnt++;
}
}
System.out.print(cnt);
}
}
i & ( i - 1) == 0
import java.util.*
导入将数组二分,调整左半部分,从左半部分最右侧元素开始,向左遍历,若该元素与其左侧相邻元素同时大于(小于)右半部分对应元素,将两者同时减(加)一,否则单独调整该元素,注意单独调整第一个元素(无左侧相邻元素),记录总的调整次数。
将数组二分,先将左半部分元素替换为a[i] - a[n - i -1]
,再从左向右遍历左半部分(从右向左同理),记录将当前元素调整为零的次数(即a[i]的绝对值),若与其右侧相邻元素同号,则对其相邻元素同时进行调整,注意单独调整最后一个元素(无右侧相邻元素),记录总的调整次数。
两种思路其实本质相同,只是思路二将思路一中一次一次调整计数优化为直接调整k次并计数
有双重循环,时间复杂度为O(n^2),部分用例时间超限。
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n];
long cnt = 0;
for(int i = 0; i < n; i++){
a[i] = sc.nextInt();
}
for(int i = n / 2 - 1; i > 0; i--){
while(a[i] != a[n - 1 - i]){
if(a[i] < a[n - 1 - i]){
a[i]++;
if(a[i - 1] < a[n - i]){
a[i - 1]++;
}
} else {
a[i]--;
if(a[i - 1] > a[n - i]){
a[i - 1]--;
}
}
cnt++;
}
}
cnt += Math.abs(a[0] - a[n - 1]);
System.out.print(cnt);
}
}
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n];
long cnt = 0L;
for(int i = 0; i < n; i++){
a[i] = sc.nextInt();
}
for(int i = 0; i < n / 2; i++){
a[i] = a[i] - a[n - 1 - i];
}
for(int i = 0; i < n / 2 - 1; i++){
cnt += Math.abs(a[i]);
if(a[i] > 0 == a[i + 1] > 0){
a[i + 1] = Math.abs(a[i]) > Math.abs(a[i + 1]) ? 0 : a[i + 1] - a[i];
}
}
cnt += Math.abs(a[n / 2 - 1]);
System.out.print(cnt);
}
}
a > 0 == b > 0
将环形字符串视为点,公共字符串长度为边权,题目就是让求最大生成树。
第一步,求出所有边权,可以使用动态规划。
第二步,求出最大生成树的边权之和,可以使用Kruskal算法 。
以下代码源自网络——原链接
import java.util.*;
import java.io.*;
public class Main {
private static char[][] arr;
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(System.out);
StringTokenizer st = new StringTokenizer(in.readLine());
int n = Integer.parseInt(st.nextToken());
int m = Integer.parseInt(st.nextToken());
// 每个字符串重复自己
arr = new char[n][m * 2];
for (int i = 0; i < n; i++) {
char[] s = in.readLine().toCharArray();
for (int j = 0; j < m; j++) {
arr[i][j] = arr[i][j + m] = s[j];
}
}
// 求所有边权
int[][] dist = new int[n][n];
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
dist[i][j] = lcs(i, j);
}
}
// 所有边入堆
Queue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt((int[] a) -> -a[2]));
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
pq.offer(new int[]{i, j, dist[i][j]});
}
}
// Kruskal 算法
int[] root = new int[n];
Arrays.setAll(root, a -> a);
int take = 0;
int ans = 0;
while (take < n - 1) {
int[] p = pq.poll();
if (find(root, p[0]) != find(root, p[1])) {
union(root, p[0], p[1]);
take++;
ans += p[2];
}
}
out.println(ans);
out.flush();
out.close();
}
// 求两旋转字符串的最长公共子串长度
private static int lcs(int x, int y) {
int m = arr[0].length;
int max = 0;
int[][] dp = new int[m + 1][m + 1];
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= m; j++) {
if (arr[x][i - 1] == arr[y][j - 1]) {
dp[i][j] = Math.max(dp[i - 1][j - 1] + 1, dp[i][j]);
max = Math.max(dp[i][j], max);
}
}
}
return Math.min(max, m / 2);
}
// 并查集
private static int find(int[] root, int i) {
return root[i] == i ? i : (root[i] = find(root, root[i]));
}
// 并查集
private static void union(int[] root, int x, int y) {
root[find(root, x)] = find(root, y);
}
}
属于博弈问题,初始必败态为0、1,根据SG函数的定义求解即可。
SG函数学习——博弈问题与SG函数
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
int[] n0 = new int[T];//存储原输入顺序
int[] n = new int[T];
for (int i = 0; i < T; i++) {
n0[i] = n[i] = sc.nextInt();
}
Arrays.sort(n);
int maxn = n[T - 1];
int[] sg = new int[maxn + 1];
int[] primes = new int[maxn + 1];
for (int i = 0; i <= maxn; i++) {
sg[i] = 0;
}
for (int i = 0; i <= maxn; i++) {
primes[i] = i;
}
//埃氏筛
for (int i = 2; i <= maxn / 2; i++) {
if (primes[i] != -1) {
for (int j = 2 * i; j <= maxn; j += i) {
primes[j] = -1;
}
}
}
//简便起见,SG函数值直接使用0\1
for (int i = 2; i <= maxn; i++) {
for (int j = i; j >= 2; j--) {
if (primes[j] != -1 && sg[i - j] == 0) {
sg[i] = 1;
break;
}
}
}
for (int i = 0; i < T; i++) {
System.out.println(sg[n0[i]]);
}
}
}
Arrays.sort
对数组排序,使用Arrays.binarySearch
二分查找元素并返回下标,使用Arrays.copyOf
复制数组并返回数组,使用Arrays.fill
方法填充数组,使用Arrays.equals
方法判断数组是否相等并返回布尔结果。一般情况下将字符串分为3部分:连续的lbq组合(str1)+其余字符+连续的lbq组合(str2),如lb/nbn/ql。
分类讨论:
需要注意的是,均为lbq时可构成回文。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
String str = new String();
String lbq = "lbq";
sc.nextLine();//nextInt()不读空白符
for (int i = 0; i < n; i++) {
str = sc.nextLine();
int len = str.length(), len1 = 0, len2 = 0;
int left = 0, right = len - 1;
while (right >= 0 && lbq.indexOf(str.charAt(right--)) != -1) {
len2++;
}
//先右后左,再通过left < right 的约束使得均为特殊字符时len1为0
while (left < right && lbq.indexOf(str.charAt(left++)) != -1) {
len1++;
}
if (len1 > len2) {
System.out.println("No");
} else if (isPLR(str.substring(0, len - len2 + len1))) {
System.out.println("Yes");
} else {
System.out.println("No");
}
}
}
public static boolean isPLR(String str) {
int left = 0;
int right = str.length() - 1;
while (left < right) {
if (str.charAt(left) != str.charAt(right)) {
return false;
}
left++;
right--;
}
return true;
}
}
contains
参数为字符串,indexOf
参数为字符,用contains
判断字符串内是否含有字符时,需要用String.valueOf
将字符转换为字符串nextInt
不读空白符,next
以空白符为间隔,nextLine
以换行符为间隔,在nextInt
后直接使用nextLine
时,需要注意中间有没有换行符,处理不当可能导致nextLine
只读取换行符。难度太大,网上也没找到答案,不必浪费时间,有能力再补。