【蓝桥杯】枚举、模拟与排序

此题可以先思考暴力解法,即用三层for循环去解

for (int i = 0; i < n; i++){ // 枚举左端点
    for (int j = i; j < n; j++){ // 枚举右端点
        for (int k = 0; k < n; k++){
            //得到区间[i,j]
            对区间进行排序,排序后在挨个检查是否后一个数比前一个数严格+1
        }
    }
}

观察题目可以知道,区间最大值-区间最小值一定满足 关系 a[j] - a[i] == j - i;

因为最小到最大差距为 i - j + 1

import java.util.*;

class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        
        int N = 10010;
        int[] a = new int[N];
        
        int n = sc.nextInt();
        
        for (int i = 0; i < n; i++){
            a[i] = sc.nextInt();
        }
        
        int res = 0;
        // 枚举左端点
        for (int i = 0; i < n; i++){
            int max = -1;
            int min = 10001;
            
            // 枚举右端点
            for (int j = i; j < n; j++){
                min = Math.min(min,a[j]);
                max = Math.max(max,a[j]);
                
                if (max - min == (j - i)){
                    res++;
                }
            }
        }
        
        System.out.print(res);
        
    }
}

从暴力思维出发,此题最容易想到的做法就是用三层for循环去枚举,就不说了

两个方法:前缀和和二分法

前缀和的思路是 先把a[i] 和 c[i]出现的次数去统计,s[i] 表示 前i个数出现的总和

import java.util.*;

class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        
        int N = 100010;
        
        int[] a = new int[N]; // 存放A数组
        int[] b = new int[N]; // 同理
        int[] c = new int[N];
        
        int[] as = new int[N]; // as[i] 表示 有多少个数小于 b[i]
        int[] cs = new int[N]; // cs[i] 表示 有多少个数大于 b[i];
        
        int[] cnt = new int[N]; // 统计 a[i] 和 c[i] 出现的个数
        int[] s = new int[N]; // 前缀和数组
        
        int n = sc.nextInt();
        
        for (int i = 0; i < n; i++) a[i] = sc.nextInt();
        for (int i = 0; i < n; i++) b[i] = sc.nextInt();
        for (int i = 0; i < n; i++) c[i] = sc.nextInt();
        
        for (int i = 0; i < n; i++){
            a[i]++;
            b[i]++;
            c[i]++;
            // 将数字脱离0,方便前缀和计算
        }
        
        // 计算as
        for (int i = 0; i < n; i++) cnt[a[i]]++;
        for (int i = 1; i < N; i++) s[i] = s[i-1] + cnt[i];
        for (int i = 0; i < n; i++) as[i] = s[b[i] - 1]; // 表示有多少个数比b【i】小
        
        // 计算cs
        cnt = new int[N];
        s = new int[N];
        for (int i = 0; i < n; i++) cnt[c[i]]++;
        for (int i = 1; i < N; i++) s[i] = s[i-1] + cnt[i];
        for (int i = 0; i < n; i++) cs[i] = s[N-1] - s[b[i]]; // 表示有多少个数比b【i】大
        
        long res = 0;
        for (int i = 0; i < n; i++){
            res += ((long)as[i] * (long)cs[i]);
        }
        
        System.out.print(res);
        
    }
}


二分法:
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();


        int[] a = new int[n]; // 存放A数组
        int[] b = new int[n]; // 同理
        int[] c = new int[n];


        for (int i = 0; i < n; i++) a[i] = sc.nextInt();
        for (int i = 0; i < n; i++) b[i] = sc.nextInt();
        for (int i = 0; i < n; i++) c[i] = sc.nextInt();

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

        int left;
        int right;

        long res = 0;
        int as = 0;
        int cs = 0;

        for (int i = 0; i < n; i++){
            int bi = b[i];
            left = 0;
            right = n - 1;

            while (left < right){
                int mid = (left + (right + 1)) / 2;

                if (a[mid] < bi) left = mid;
                else right = mid - 1;
            }

            as = a[left] < bi ? left : -1;

            left = 0;
            right = n - 1;
            while (left < right){
                int mid = (left + right) / 2;

                if (c[mid] > bi) right = mid;
                else left = mid + 1;
            }

            cs = c[left] > bi ? left : -1;

            if (as != -1 && cs != -1){
                res += ( (as + 1) * (n - cs));
            }
        }



        System.out.println(res);
    }

1、通过对输入的编号进行排序

2、从小到大遍历
(1)由于重号只会出现一个,因此当a[i] == a[i - 1]时,a[i]表示重号
(2)由于断号只会出现一个,因此一定会空缺一个数,则当a[i] == a[i - 1] + 2时,a[i] - 1表示断号

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;

public class Main {
    static int[] a = new int[100010];
    static int k = 0;
    public static void main(String[] args) throws IOException{
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(reader.readLine().trim());
        while(n -- > 0)
        {
            String[] s1 = reader.readLine().split(" ");
            for(int i = 0;i < s1.length;i++)
            {
                a[k ++] = Integer.parseInt(s1[i]);
            }
        }
        Arrays.sort(a,0,k);
        int res1 = -1;//断号(只会断一次)
        int res2 = -1;//重号
        for(int i = 1;i < k;i++)
        {
            if(a[i] == a[i - 1]) res2 = a[i];//重号
            else if(a[i] == a[i - 1] + 2) res1 = a[i] - 1;//断号
        }
        System.out.println(res1 + " " + res2);
    }
}

暴力思路:枚举10000000 -》 99999999 间的数字去判断日期合法并回文

解题思路:

1.先写回文

2.判断日期在给定日期之间

3.判断是否为合法日期

import java.util.*;

class Main{
    public static void main(String[] args)  {
        Scanner sc = new Scanner(System.in);

        int date1 = sc.nextInt();
        int date2 = sc.nextInt();
        int res = 0;

        for (int i = 1000; i < 10000; i++) {
            int date = i;
            int x = i;

            for (int j = 0; j < 4; j++) {
                date = date * 10 + x % 10;
                x /= 10;
            }

            if (date1 <= date && date <= date2 && check(date)) res++;
        }

        System.out.println(res);
    }

    static int[] days = {0,31,28,31,30,31,30,31,31,30,31,30,31};
    public static boolean check(int date){
        int year = date / 10000;
        int month = date % 10000 / 100;
        int day = date % 100;

        if (month == 0 || month > 12) return false;
        if (day == 0 || (month != 2 && day > days[month])) return false;
        if (month == 2){
            if ((year % 100 != 0 && year % 4 == 0) || year % 400 == 0){
                if (day > 29) return false;
            }
        }

        return true;
    }
}

最短移动距离 = 曼哈顿距离

将奇数行的数据翻转:w - 1 - y1

import java.util.*;

class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        
        int w = sc.nextInt();
        int m = sc.nextInt();
        int n = sc.nextInt();
        
        n--;
        m--;
        
        int x1 = m / w;
        int y1 = m % w;
        int x2 = n / w;
        int y2 = n % w;
        
        if (x1 % 2 != 0) y1 = w - 1 - y1;
        if (x2 % 2 != 0) y2 = w - 1 - y2;
        
        System.out.print(Math.abs(x1-x2) + Math.abs(y1-y2));
    }
}

m--和n--是因为借鉴了正常的数组的表示方式,从下标0开始。即可以推出行号 = n / w;

列号也是一样。

1.枚举8位数

2.判断是否为合法日期

3.判断是否满足条件

import java.util.*;
import java.io.*;
class Main{
    
    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));

        String[] arr = bf.readLine().split("/");
        // arr : a/b/c
        // a/b/c || c/a/b || c/b/a
        int a = Integer.parseInt(arr[0]);
        int b = Integer.parseInt(arr[1]);
        int c = Integer.parseInt(arr[2]);

        for (int date = 19600101; date <= 20591231; date++) {
            int year = date / 10000;
            int month = date % 10000 / 100;
            int day = date % 100;

            if (check(year,month,day)){
                if ( (year % 100 == a && month == b && day == c) || (year % 100 == c && month == a && day == b) || (year % 100 == c && month == b && day == a) ){
                    System.out.printf("%d-%02d-%02d",year,month,day);
                    System.out.println();
                }
            }
        }
    }

    static int[] days = {0,31,28,31,30,31,30,31,31,30,31,30,31};
    public static boolean check(int year,int month,int day){
        if (day <= 0 || month > 12) return false;
        if (month != 2 && (day > days[month])) return false;
        if (month == 2){
            if ((year % 100 != 0 && year % 4 == 0) || year % 400 == 0){
                if (day > 29) return false;
            }else {
                if (day > 28) return false;
            }
        }

        return true;
    }
    
}

printf中 "%02d"表示不足2位时补0

有时间time:
hour = time / 3600

min = time % 3600 / 60

second = time % 60

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
蓝桥杯常用的枚举法有两种:排列型枚举和组合型枚举。其,排列型枚举是指从n个元素取m个元素进行排列,而组合型枚举是指从n个元素取m个元素进行组合。下面以一个例子来介绍排列型枚举的实现方法。 假设有n个元素,需要从选出m个元素进行排列,可以使用递归的方式实现。具体实现方法如下: ```python import numpy as np chosen = [] # 存储已选元素 n = 0 # 元素总数 m = 0 # 需要选出的元素个数 def calc(x): """ 递归函数,从第x个元素开始选取 """ if len(chosen) > m: # 已选元素个数超过m个,返回 return if len(chosen) + n - x + 1 < m: # 剩余元素个数不足m个,返回 return if x == n + 1: # 已经选完n个元素,输出结果 for i in chosen: print(i, end=' ') print(' ') return chosen.append(x) # 选取第x个元素 calc(x + 1) # 递归选取下一个元素 chosen.pop() # 不选第x个元素 calc(x + 1) # 递归选取下一个元素 if __name__ == '__main__': tem = input().split() n = int(tem[0]) m = int(tem[1]) calc(1) # 从第1个元素开始选取 ``` 以上代码实现了从n个元素选取m个元素进行排列的功能,其chosen列表存储已选元素,calc函数为递归函数,从第x个元素开始选取,如果已选元素个数超过m个或剩余元素个数不足m个,则返回;如果已经选完n个元素,则输出结果;否则,选取第x个元素或不选第x个元素,递归选取下一个元素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值