1. NC255193 水果大礼包
题目描述
游游有
n个苹果,m个桃子。她可以:
把 2 个苹果和 1 个桃子 组成价值
a元的一号水果大礼包;把 1 个苹果和 2 个桃子 组成价值
b元的二号水果大礼包。问:最多能组成多少价值总和的大礼包?
输入描述
四个正整数
n, m, a, b,用空格隔开。
1 ≤ n, m, a, b ≤ 10^6输出描述
一个整数,代表大礼包的最大价值总和。
示例
text
输入:3 4 1 2 输出:4说明:组成两个二号水果大礼包,使用了 2 个苹果和 4 个桃子,总价值为 4。
为什么贪心是错的?
一个直觉思路是:哪个礼包单价高,就优先做哪个。比如 a > b 就尽量多做一号礼包,剩下的材料再做二号礼包。
这个贪心是错误的。原因很简单:礼包单价高,不代表资源利用率高。多做高单价礼包可能会占用过多某种水果,导致另一种礼包做不了,最终总价值反而更低。
举个反例:
text
n = 5, m = 7, a = 6, b = 5按照贪心,
a > b,优先做一号礼包:
一号礼包最多做
min(5/2, 7/1) = 2个,消耗 4 苹果、2 桃子;剩余 1 苹果、5 桃子,只能做 1 个二号礼包;
总价值:
6 × 2 + 5 × 1 = 17。但如果只做 1 个一号礼包:
消耗 2 苹果、1 桃子;
剩余 3 苹果、6 桃子,可以做 3 个二号礼包;
总价值:
6 × 1 + 5 × 3 = 21。21 > 17,贪心策略失败。
所以这道题不能直接贪心,需要枚举一号礼包的数量,对每种情况计算二号礼包数量,取最大值。
正确思路:枚举一号礼包数量
一号礼包最多做
min(n/2, m)个。枚举一号礼包数量i:
剩余苹果:
n - 2i剩余桃子:
m - i二号礼包数量:
min(n - 2i, (m - i) / 2)总价值:
a * i + b * y取所有枚举结果的最大值。
时间复杂度:
O(min(n/2, m)),最坏O(10^6),可接受。
参考代码(Java):贪心错误代码贪心错误代码
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt(), m = in.nextInt(), a = in.nextInt(), b = in.nextInt();
long sum = 0;
if(a > b) {
while(n >= 2 && m >= 1) {
sum += a;
n -= 2;
m -= 1;
}
while(n >= 1 && m >= 2) {
sum += b;
n -= 1;
m -= 2;
}
} else {
while(n >= 1 && m >= 2) {
sum += b;
n -= 1;
m -= 2;
}
while(n >= 2 && m >= 1) {
sum += a;
n -= 2;
m -= 1;
}
}
System.out.println(sum);
}
}
参考代码(Java)
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
long n = in.nextLong(), m = in.nextLong(), a = in.nextLong(), b = in.nextLong();
long sum = 0;
for(long i = 0; i <= Math.min(n / 2, m); i++) {
long y = Math.min(n - i * 2, (m - i) / 2);
sum = Math.max(sum, (long)a * i + b * y);
}
System.out.println(sum);
}
}
2. DP31 买卖股票的最好时机(二)
题目描述
假设你有一个数组 prices,长度为 n,其中 prices[i] 是某只股票在第 i 天的价格,请根据这个价格数组,返回买卖股票能获得的最大收益。
规则:
你可以多次买卖该只股票,但是再次购买前必须卖出之前的股票;
如果不能获取收益,请返回 0;
假设买入卖出均无手续费。
数据范围
0 ≤ n ≤ 1 × 10^5
1 ≤ prices[i] ≤ 10^4要求:空间复杂度
O(n),时间复杂度O(n)。
进阶:空间复杂度O(1),时间复杂度O(n)。输入描述
第一行输入一个正整数
n,表示数组prices的长度;第二行输入
n个正整数,表示数组中prices的值。输出描述
输出最大收益。
示例
text
输入: 7 8 9 2 5 4 7 1 输出: 7
思路分析
因为可以多次买卖,且无手续费,所以只要后一天价格比前一天高,就可以在前一天买入、后一天卖出,赚取差价。
把所有相邻两天的正收益累加,就是最大收益。
这等价于动态规划中的状态转移:
dp[i][0]:第i天不持股的最大收益;
dp[i][1]:第i天持股的最大收益。但由于允许无限次交易且无手续费,最优策略就是“逢涨就赚”,因此可以简化为贪心。
只要当天的价钱比第二天的价格低,我就记录到sum里面
import java.util.*;
import java.io.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] price = new int[n + 1];
int sum = 0;
for(int i = 0; i < n; i++) {
price[i] = in.nextInt();
if(i != 0 && price[i] > price[i - 1]) {
sum += price[i] - price[i - 1];
}
}
System.out.println(sum);
}
}
class Read {
StringTokenizer st = new StringTokenizer(" ");
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
String next() throws IOException {
while(!st.hasMoreTokens()) {
st = new StringTokenizer(bf.readLine());
}
return st.nextToken();
}
int nextInt() throws IOException {
return Integer.parseInt(next());
}
}
3. REAL506 倒置字符串
题目描述
将一句话的单词进行倒置,标点不倒置。比如
I like beijing.经过函数后变为:beijing. like I。输入描述
每个测试输入包含 1 个测试用例:
I like beijing.输入用例长度不超过 100。输出描述
依次输出倒置之后的字符串,以空格分割。
示例
text
输入:I like beijing. 输出:beijing. like I思路分析
步骤:
先将整个字符串整体反转,得到
.gnijieb ekil I;再对每个单词局部反转,得到
beijing. like I。或者:
先按空格分割单词;
从后往前拼接单词,用空格连接。
本题参考代码采用整体反转 + 单词局部反转的方式,原地操作字符数组。
参考代码(Java)
import java.util.*;
import java.io.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void Reverse(char[] s, int left, int right) {
while(left < right) {
char ch = s[left];
s[left] = s[right];
s[right] = ch;
left++;
right--;
}
}
public static void main(String[] args) throws Throwable{
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
char[] s = in.readLine().toCharArray();
int n = s.length;
Reverse(s, 0, n - 1);
int left = 0;
while(left < n) {
int right = left;
while(right < n && s[right] != ' ') right++;
Reverse(s, left, right - 1);
while(right < n && s[right] == ' ') right++;
left = right;
}
for(char ch : s) System.out.print(ch);
}
}
、REAL506 倒置字符串&spm=1001.2101.3001.5002&articleId=164885344&d=1&t=3&u=74b89f54aedd4465a2e44c22e86c03b6)
59

被折叠的 条评论
为什么被折叠?



