0
点赞
收藏
分享

微信扫一扫

蓝桥杯31天冲刺打卡题解(Day8)

hwwjian 2022-03-15 阅读 79

Day8

第一题

第五届2014年蓝桥杯省赛

神奇算式

JavaA组第3题

填空题

利用Set集合去重,并判断set的大小是否为4

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        int cnt = 0;
        for (int i = 1; i <= 987; i++) {
            for (int j = i; j <= 987; j++) {
                int res = i * j;
                if (res >= 10000) continue;
                String s1 = i + "" + j;
                String s2 = res + "";
                char[] c1 = s1.toCharArray();
                char[] c2 = s2.toCharArray();
                if (check(c1, c2)) cnt++;
            }
        }
        System.out.println(cnt);
    }

    private static boolean check(char[] c1, char[] c2) {
        Arrays.sort(c1);
        Arrays.sort(c2);
        String s1 = String.valueOf(c1);
        String s2 = String.valueOf(c2);
        if (s1.equals(s2) && check_reduplicate(s2)) {
            return true;
        }
        return false;
    }
    
    // 判重
    private static boolean check_reduplicate(String s) {
        Set<String> set = new HashSet<>();
        for (int i = 0; i < s.length(); i++) {
        	set.add(s.charAt(i) + "");
        }
        if (set.size() == 4) {
            return true;
        }
        return false;
    }
}

第二题

第九届2018年蓝桥杯省赛

缩位求和

JavaC组第6题

简单的字符串处理问题。

import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		String a = sc.next();
		while (a.length() > 1) {
			int sum = 0;
			for (int i = 0; i < a.length(); i++) {
				sum += a.charAt(i) - '0'; // 转为int类型
			}
			String b = sum + ""; // 转为String类型
			a = b; // 重新赋值 再次拆分
		}
		System.out.println(a); // 此时a只剩一位	
	}
}

第三题

NOIP2013提高组

积木大赛

贪心+差分

给定一个区间[L,R][L, R],每次操作可以使这个区间所有积木数+1,现在就是给我们一个大厦的宽度n以及每1个宽度需要的积木数,让我们求最少操作多少次可以建成大厦,不难看出是一道贪心题目,使我们的区间尽量大。

我们可以把过程逆过来,因为我们已经知道了每堆积木的高度,所以我们可以将某一段区间所有高度-1,求我们操作多少次可以把所有高度变为0

看第一个样例:

操作所有数,全部-1

image-20220315193023626

再操作前3个数:

image-20220315193123659

再操作第2、3个数:

image-20220315193200812

然后再分别操作第3个数和第5个数,总操作数为5

image-20220315193259672

我们试着用差分来解决这道题,将原数组 hih_i 变为差分数组 bib_i =>bi=hihi1=> b_i = h_i - h_{i - 1}

原数组:h1,h2...h3h_1, h_2 ... h_3

差分数组:

b1=h1b_1 = h_1

$b_2 = h_2 - h_1 $

​ $… $

bn=hnhn1b_n = h_n - h_{n-1}

bn+1=hnb_{n+1} = -h_n

当我们想让区间[L,R][L, R]的所有数 hL,hL+1...hRh_L,h_{L+1}...h_R 全部-1,我们只需要改差分数组的两个值就可以,bL=hLhL1b_L = h_L-h_{L-1}hL1h_{L-1}不变,hLh_{L} 减了1,所以 bLb_{L} 减了1;bL+1=hL+1hLb_{L+1} = h_{L+1}-h_{L}hL+1h_{L+1}hLh_{L} 都减了1,差值不变,所以 bL+1b_{L+1} 不变,以此类推剩下的都不变,但当bR+1=hR+1hRb_{R + 1} = h_{R + 1} - h_R 时,hR+1h_{R + 1} 不变,hRh_R 减了1,所以是让 bR+1b_{R + 1} 加了1。

综上,如果对原数组的区间[L.R][L. R]所有值全部减1,那么对应到差分数组我们只改变了两个值:一个是 bLb_L 减1,另一个是 bR+1b_{R + 1} 加1。

原数组任意的区间操作都可以对应到差分数组两个数的操作,而且是一一对应的。

我们要使原数组所有数变成0,那么差分数组也全部变成0,相当于我们每次要从差分数组 b1,b2...bn+1b_1, b_2 ... b_{n + 1} 挑两个数,前一个减1,后一个加1,求最少操作多少次可以将所有数变成0。

我们每一次从前往后看,找到第一个大于0的 bib_i,我们从后面任意找一个负数 bjb_jbib_i 配对,然后让 bib_i 减1, bjb_j 加1即可。

image-20220315203121506

我们如何确定我们一定能在 bib_i 后面找到一个负数呢?

image-20220315204145655

把所有 bib_i 拆分成原数组,所有项全部都消掉了,只剩下了 hi1-h_{i - 1}

我们发现:因为所有hi0h_i \geqslant 0,所以 bi+...+bn+1b_i+ ...+b_{n + 1} 一定是小于等于0的,所以当 bi>0b_i > 0 时, bi+1+...+bn+1b_{i+1}+ ...+b_{n + 1} 一定是严格小于0的,所以 bib_i 后面必然存在一个负数。

综上,证明完毕。

求出差分数组并扫描一遍即可。

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

import java.util.Scanner;

public class Main {
    
    static final int N = 100010;
    static int[] h = new int[N]; // 原数组
    static int[] b = new int[N]; // 差分数组
    
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        for (int i = 1; i <= n; i++) h[i] = sc.nextInt();
        
        for (int i = 1; i <= n + 1; i++) b[i] = h[i] - h[i - 1]; // 差分数组 i要取到n + 1
        
        int res = 0;
        for (int i = 1; i <= n + 1; i++) {
            if (b[i] > 0) res += b[i]; // 只要b[i] > 0 我们就至少需要操作一次
        }
        
		System.out.println(res);
	}
}
举报

相关推荐

0 条评论