2-18算法习题总结

二分查找问题

[COCI 2011/2012 #5] EKO / 砍树

题目描述

伐木工人 Mirko 需要砍 M M M 米长的木材。对 Mirko 来说这是很简单的工作,因为他有一个漂亮的新伐木机,可以如野火一般砍伐森林。不过,Mirko 只被允许砍伐一排树。

Mirko 的伐木机工作流程如下:Mirko 设置一个高度参数 H H H(米),伐木机升起一个巨大的锯片到高度 H H H,并锯掉所有树比 H H H 高的部分(当然,树木不高于 H H H 米的部分保持不变)。Mirko 就得到树木被锯下的部分。例如,如果一排树的高度分别为 20 , 15 , 10 20,15,10 20,15,10 17 17 17,Mirko 把锯片升到 15 15 15 米的高度,切割后树木剩下的高度将是 15 , 15 , 10 15,15,10 15,15,10 15 15 15,而 Mirko 将从第 1 1 1 棵树得到 5 5 5 米,从第 4 4 4 棵树得到 2 2 2 米,共得到 7 7 7 米木材。

Mirko 非常关注生态保护,所以他不会砍掉过多的木材。这也是他尽可能高地设定伐木机锯片的原因。请帮助 Mirko 找到伐木机锯片的最大的整数高度 H H H,使得他能得到的木材至少为 M M M 米。换句话说,如果再升高 1 1 1 米,他将得不到 M M M 米木材。

输入格式

1 1 1 2 2 2 个整数 N N N M M M N N N 表示树木的数量, M M M 表示需要的木材总长度。

2 2 2 N N N 个整数表示每棵树的高度。

输出格式

1 1 1 个整数,表示锯片的最高高度。

样例 #1

样例输入 #1

4 7
20 15 10 17

样例输出 #1

15

样例 #2

样例输入 #2

5 20
4 42 40 26 46

样例输出 #2

36

提示

对于 100 % 100\% 100% 的测试数据, 1 ≤ N ≤ 1 0 6 1\le N\le10^6 1N106 1 ≤ M ≤ 2 × 1 0 9 1\le M\le2\times10^9 1M2×109,树的高度 ≤ 4 × 1 0 5 \le 4\times 10^5 4×105,所有树的高度总和 > M >M >M

这道题我还没写出来

动态规划问题

疯狂的采药

题目背景

此题为纪念 LiYuxiang 而生。

题目描述

LiYuxiang 是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同种类的草药,采每一种都需要一些时间,每一种也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是 LiYuxiang,你能完成这个任务吗?

此题和原题的不同点:

1 1 1. 每种草药可以无限制地疯狂采摘。

2 2 2. 药的种类眼花缭乱,采药时间好长好长啊!师傅等得菊花都谢了!

输入格式

输入第一行有两个整数,分别代表总共能够用来采药的时间 t t t 和代表山洞里的草药的数目 m m m

2 2 2 到第 ( m + 1 ) (m + 1) (m+1) 行,每行两个整数,第 ( i + 1 ) (i + 1) (i+1) 行的整数 a i , b i a_i, b_i ai,bi 分别表示采摘第 i i i 种草药的时间和该草药的价值。

输出格式

输出一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。

样例 #1

样例输入 #1

70 3
71 100
69 1
1 2

样例输出 #1

140

提示

数据规模与约定

  • 对于 30 % 30\% 30% 的数据,保证 m ≤ 1 0 3 m \le 10^3 m103
  • 对于 100 % 100\% 100% 的数据,保证 1 ≤ m ≤ 1 0 4 1 \leq m \le 10^4 1m104 1 ≤ t ≤ 1 0 7 1 \leq t \leq 10^7 1t107,且 1 ≤ m × t ≤ 1 0 7 1 \leq m \times t \leq 10^7 1m×t107 1 ≤ a i , b i ≤ 1 0 4 1 \leq a_i, b_i \leq 10^4 1ai,bi104

最后一个测试点没过

代码如下:

package exercise.luogu.dp;

import java.util.Scanner;

public class P1616 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        int n = sc.nextInt();
        int[] val = new int[n];
        int[] time = new int[n];
        int dp[] = new int[t + 1];

        for (int i = 0; i < n; i++) {
            time[i] = sc.nextInt();
            val[i] = sc.nextInt();
        }
        // 完全背包问题:每种药材都可以采多次
        for (int i = 0; i < n; i++) { // 遍历每种药材
            for (int j = time[i]; j <= t; j++) { // 遍历背包容量,注意从time[i]开始
                // 当前药材可以放入背包中,比较放入与不放入哪种情况价值更高
                dp[j] = Math.max(dp[j], dp[j - time[i]] + val[i]);
            }
        }
        System.out.println(dp[t]);
    }
}

总结:
我感觉完全背包问题部分背包问题要简单得多!

贪心问题

删数问题

题目描述

键盘输入一个高精度的正整数 N N N(不超过 250 250 250 位),去掉其中任意 k k k 个数字后剩下的数字按原左右次序将组成一个新的非负整数。编程对给定的 N N N k k k,寻找一种方案使得剩下的数字组成的新数最小。

输入格式

输入两行正整数。

第一行输入一个高精度的正整数 n n n

第二行输入一个正整数 k k k,表示需要删除的数字个数。

输出格式

输出一个整数,最后剩下的最小数。

样例 #1

样例输入 #1

175438 
4

样例输出 #1

13

代码如下:

package exercise.luogu.greedy;

import java.util.Scanner;
import java.util.Stack;

public class P1106 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str = sc.next();
        int k = sc.nextInt();
        char[] charArray = str.toCharArray();
        Stack<Character> stack = new Stack<>();
        int removeCount = 0;

        for (int i = 0; i < charArray.length; i++) {
            //如果栈顶元素大于当前元素,pop出栈顶元素,把当前元素加入栈
            while (!stack.isEmpty() && stack.peek() > charArray[i] && removeCount < k) {
                stack.pop();
                removeCount++;
            }
            stack.push(charArray[i]);
        }
        // 如果还有需要删除的数字,则从栈顶开始删除
        while (removeCount < k) {
            stack.pop();
            removeCount++;
        }
        // 将栈中的数字转换为字符串并输出
        StringBuilder sb = new StringBuilder();
        while (!stack.isEmpty()) {
            sb.append(stack.pop());
        }
        sb.reverse(); // 因为栈是后进先出的,所以需要反转字符串才能得到正确的结果
        System.out.println(Integer.parseInt(sb.toString()));
    }
}

分支问题

【模板】快速幂

题目描述

给你三个整数 a , b , p a,b,p a,b,p,求 a b   m o d   p a^b \bmod p abmodp

输入格式

输入只有一行三个整数,分别代表 a , b , p a,b,p a,b,p

输出格式

输出一行一个字符串 a^b mod p=s,其中 a , b , p a,b,p a,b,p 分别为题目给定的值, s s s 为运算结果。

样例 #1

样例输入 #1

2 10 9

样例输出 #1

2^10 mod 9=7

提示

样例解释

2 10 = 1024 2^{10} = 1024 210=1024 1024   m o d   9 = 7 1024 \bmod 9 = 7 1024mod9=7

数据规模与约定

对于 100 % 100\% 100% 的数据,保证 0 ≤ a , b < 2 31 0\le a,b < 2^{31} 0a,b<231 a + b > 0 a+b>0 a+b>0 2 ≤ p < 2 31 2 \leq p \lt 2^{31} 2p<231

代码如下:

package exercise.luogu.fenzhi;

import java.util.Scanner;

public class P1226 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        int b = sc.nextInt();
        int p = sc.nextInt();
        int s = fastPowMod(a, b, p);
        System.out.printf("%d^%d mod %d=%d", a, b, p, s);
    }

    //快速幂算法
    private static int fastPowMod(int a, int b, int p) {
        if (b == 0) {
            return 1;
        }

        int halfMod = fastPowMod(a, b / 2, p);
        int modSquare = (int) (((long) halfMod * halfMod) % p);

        //如果 b 是偶数,那么 a^b = (a^(b/2))^2。
        if (b % 2 == 0) {
            return modSquare;
        } else {//如果 b 是奇数,那么 a^b = a * (a^(b-1))。
            //我们首先计算 a^((b-1)/2) mod p(这仍然是 halfMod,因为整数除法会向下取整)
            return (int) (((long) modSquare * a) % p);
        }
    }
}

  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知意..

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值