0
点赞
收藏
分享

微信扫一扫

蓝桥杯AcWing学习笔记 4-1枚举的学习(附相关蓝桥真题:连号区间数、递增三元组、特别数的和)(Java)

岛上码农 2022-03-11 阅读 39

蓝桥杯

我的AcWing

题目及图片来自蓝桥杯C++ AB组辅导课

枚举

在这里插入图片描述

第四届2013年蓝桥杯真题

AcWing 1210. 连号区间数

JavaB组第10题

给一个区间 求可以成为连号区间的子区间个数

暴力枚举(超时)

时间复杂度 O ( N 3 l o g N ) O(N^3logN) O(N3logN)

利用了排序。

AcWingTLE,只过了4/10个数据,蓝桥杯只过了2/5个数据,满分100分只拿到了40分。

要注意一点:AcWing的数据范围 1 ≤ N ≤ 10000 1≤N≤10000 1N10000,而蓝桥杯的测试范围 1 ≤ N ≤ 50000 1≤N≤50000 1N50000,我们在开数组的时候要开成50010会保险一点。

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

public class Main {

    static final int N = 50010;
    static int[] a = new int[N];
    static int[] backup = new int[N]; // 拷贝数组

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        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++) {
            for (int j = i; j < n; j++) {
                backup = Arrays.copyOf(a, a.length); // 将数据存在拷贝数组中
                Arrays.sort(a, i,j + 1); // 对区间进行排序
                boolean flag = true;
                for (int k = i; k < j; k++) {
                    if (a[k + 1] - a[k] != 1) {
                        flag = false;
                        break;
                    }
                }
                if (flag) res++;
                a = Arrays.copyOf(backup, backup.length); // 还原a数组初始状态
            }
        }
        System.out.println(res);
    }
}

数学规律优化(AC)

时间复杂度 O ( N 2 ) O(N^2) O(N2)

我们发现一段数字:[8, 1, 2, 3, 4, 5, 10],连号区间 [ i , j ] [i, j] [i,j] 是第2个数~第6个数,连号区间的最大值是5,最小值是1,我们发现一个公式: m a x − m i n = j − i max - min = j - i maxmin=ji,只要一段数字满足这个公式,那么它一定是连号区间。

import java.util.Scanner;

public class Main {

    static final int N = 50010, INF = 100000000; // INF定义为无穷大 这里只要比N大就可以
    static int[] a = new int[N];

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        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 = -INF, min = INF;
            for (int j = i; j < n; j++) { // 枚举区间右端点
                max = Math.max(max, a[j]);
                min = Math.min(min, a[j]);
                if (max - min == j - i) res++;
            }
        }
        System.out.println(res);
    }
}

第九届2018年蓝桥杯真题

AcWing 1236. 递增三元组

JavaB组第6题

暴力枚举(超时)

时间复杂度 O ( N 3 ) O(N^3) O(N3)

AcWingTLE,只过了6/12个数据,蓝桥杯只过了5/8个数据,满分100分只拿到了62分。

import java.util.Scanner;

public class Main {

    static final int N = 100010;
    static int[] a = new int[N];
    static int[] b = new int[N];
    static int[] c = new int[N];

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        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();
        
        int res = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                for (int k = 0; k < n; k++) {
                    if (a[i] < b[j] && b[j] < c[k]) res++;
                }
            }
        }
        System.out.println(res);
    }
}

优化:我们只枚举一个数组,我们可以枚举B数组: A i A_{i} Ai < < < B j B_{j} Bj < < < C k C_{k} Ck => 对于每个 B j B_{j} Bj需要求的是:① 在A数组中有多少个数小于 B j B_{j} Bj ② 在C数组中有多少个数大于 B j B_{j} Bj

前缀和优化(AC)

时间复杂度 O ( N ) O(N) O(N)

小于 B j B_{j} Bj的数可以表示为: [ 0 , [0, [0, B j B_{j} Bj − 1 ] - 1] 1],定义一个数组cntcnt[i]表示在A数组中i这个值出现多少次,for (int i = 0; i < n; i++) cnt[A[i]]++; cnt就是我们的原数组,s就是我们的前缀和数组: s [ i ] = c n t [ 0 ] + c n t [ 1 ] + . . . + c n t [ i ] s[i] = cnt[0] + cnt[1] + ... + cnt[i] s[i]=cnt[0]+cnt[1]+...+cnt[i]s[i]表示在A中0~i出现多少次,所以 s [ s[ s[ B j B_{j} Bj − 1 ] - 1] 1]就是在A数组中有多少个数小于 B j B_{j} Bj;同理可以算出来在C数组中有多少个数大于 B j B_{j} Bj

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

public class Main {

    static final int N = 100010;
    static int[] a = new int[N];
    static int[] b = new int[N];
    static int[] c = new int[N];
    static int[] as = new int[N]; // as[i]表示在a[]中有多少个数小于b[i]
    static int[] cs = new int[N]; // cs[i]表示在c[]中有多少个数大于b[i]
    static int[] cnt = new int[N];
    static int[] s = new int[N]; // 前缀和数组

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        for (int i = 0; i < n; i++) a[i] = sc.nextInt() + 1; // 这里都要+1是防止数组越界
        for (int i = 0; i < n; i++) b[i] = sc.nextInt() + 1; // 因为后续有下标-1的运算
        for (int i = 0; i < n; i++) c[i] = sc.nextInt() + 1; // 如果数组中有数为0的话就会越界

        // 求as[]
        for (int i = 0; i < n; i++) cnt[a[i]]++; // 记录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]的数量

        // 将数组初始化为0
        Arrays.fill(cnt, 0);
        Arrays.fill(s, 0);

        // 求cs[]
        for (int i = 0; i < n; i++) cnt[c[i]]++; // 记录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;
        // 枚举每个b[i]
        for (int i = 0; i < n; i++) res += (long)as[i] * cs[i];
        System.out.println(res);
    }
}

第十届2019年蓝桥杯真题

AcWing 1245. 特别数的和

JavaB组第6题

此题很简单,只需要枚举每一个数的位数再进行 if 判断即可。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int res = 0;
        for (int i = 1; i <= n; i++) {
            int x = i;
            while (x > 0) {
                int t = x % 10; // 取出x的个位
                x /= 10; // 删掉x的个位
                if (t == 2 || t == 0 || t == 1 || t == 9) {
                    res += i;
                    break;
                }

            }
        }
        System.out.println(res);
    }
}

利用String中的contains方法判断是否包含某个字符串。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int res = 0;
        for (int i = 1; i <= n; i++) {
            if (String.valueOf(i).contains("2") || String.valueOf(i).contains("0") 
             || String.valueOf(i).contains("1") || String.valueOf(i).contains("9")) {
                res += i;
            }
        }
        System.out.println(res);
    }
}
举报

相关推荐

0 条评论