小美种果树
小美在手机上种果树,只要成熟了就可以领到免费的水果了。
小美每天可以给果树浇水,果树的成长值加 x。同时也可以给果树施肥,两次施肥至少需要间隔 2 天,果树的成长值加 y。果树成长值达到 z 就成熟了。
小红想知道,最少需要多少天可以领到免费的水果。
输入描述
一行三个整数 x,y,z,分别表示浇水的成长值,施肥的成长值,果树成熟的成长值。1<=x,y,z<=
1
0
9
10^9
109
输出描述
一行一个整数,表示最少需要多少天可以领到免费的水果。
示例输入
1 2 10
输出
6
说明
第一天施肥浇水,成长值为 3。
第二天浇水,成长值为 3 + 1 = 4。
第三天浇水,成长值为 4 + 1 = 5。
第四天施肥浇水,成长值为 5 + 3 = 8。
第五天浇水,成长值为 8 + 1 = 9。
第六天浇水,成长值为 9 + 1 = 10。
果树成熟了,可以领到免费水果了!
题解
直接模拟
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int x = in.nextInt();
int y = in.nextInt();
int z = in.nextInt();
int countDay = 0;
int sum = 0;
while (sum < z) {
sum += x;
if (countDay % 3 == 0) {
sum += y;
}
countDay++;
}
System.out.println(countDay);
}
观察规律
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int x = in.nextInt();
int y = in.nextInt();
int z = in.nextInt();
//3*x+y 代表每三天一循环 第一天x+y,后两天x
int yu = z % (3 * x + y);
//是每三天的倍数
if (yu == 0) {
System.out.println(z / (3 * x + y) * 3);
}
//不是每三天的倍数
else {
//小于每三天中第一天x+y,说明再来 1天就完事
if (yu < x + y) {
System.out.println(z / (3 * x + y) * 3 + 1);
}
//小于每三天中第二天2x+y,说明再来 2天就完事
else if (yu < 2 * x + y) {
System.out.println(z / (3 * x + y) * 3 + 2);
}
//需要再三天
else {
System.out.println(z / (3 * x + y) * 3 + 3);
}
}
}
小美结账
大家一起吃饭的时候,总是小红先付钱,然后大家再把钱转给小红。
现在小红有 n 张账单,每张账单记录了有 k 个人一起吃饭,以及吃饭的消费 c,现在小红需要计算每个人需要转给小红多少钱。
由于大家都比较喜欢整数,所以大家每张账单会转给小红 ⌈ c k ⌉ \lceil \frac{c}{k} \rceil ⌈kc⌉, ⌈ x ⌉ \lceil x \rceil ⌈x⌉表示对 x x x 进行上取整。
输入描述
第一行输入两个整数 n,m(1<=n,m<=
1
0
5
10^5
105)表示账单数和除小红外的总人数(分别用1到m 表示)。
接下来 2*n 行,每 2 行表示一张账单。对于每张账单:
第一行输入两个整数 n,m(1<=n,m<=10^5)表示一起吃饭的人数,花费。
第二行输入 k-1个整数,表示除小红外有哪些人一起吃饭。
数据保证,k的总和不超过 2* 1 0 5 10^5 105。
输出描述
输出m个整数,表示每个人要给小红转账的总金额。
示例输入
2 3
3 10
1 2
4 8
1 2 3
输出
6 6 2
说明
第一张账单:第1、2个人都会给小红转 4元
第二张账单:第1、2、3个人都会给小红转 2元
因此答案为 4+2=6,4+2=6,2
题解
哈希表存每个人需要交的费用,逐步更新map的值,最终遍历输出 map 的 value
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt(); // 帐单数
int m = in.nextInt(); // 其他人数
// 记录每个人需要交的总金额
LinkedHashMap<Integer, Integer> map = new LinkedHashMap<>();
for (int i = 0; i < n; i++) {
int k = in.nextInt(); // 人数
int c = in.nextInt(); // 花费
//每个人花费
int pay = (int) Math.ceil(c * 1.0 / k);
for (int j = 0; j < k - 1; j++) {
int key = in.nextInt();
//更新每个人需要交的费用 = 原来订单的 和 当前订单的
int nowPay = map.getOrDefault(key, 0) + pay;
map.put(key, nowPay);
}
}
for (Integer i : map.values()) {
System.out.printf("%d ", i);
}
System.out.println();
}
小美的游戏
小美有一个长度为 n 的数组,她最多可以进行 k 次操作,每次操作如下:
选择两个整数 i,j (1<=i<j<=n)
选择两个整数 x,y,使得 xy =
a
i
a_i
ai
a
j
a_j
aj
将
a
i
a_i
ai 替换为 x,将
a
j
a_j
aj 替换为 y
她希望最多进行 k 次操作之后,最后数组中的元素的总和尽可能大。
输入描述
一行两个整数 n,k,表示数组的长度和操作的次数。
一行 n 个整数 a1,a2,…,an,表示数组的元素。
1 <= k < n <= 1 0 5 10^5 105
1 <= a i a_i ai <= 1 0 5 10^5 105
输出描述
输出一个整数,表示最后数组中的元素的总和的最大值,由于答案可能很大,你只需要输出答案对 1 0 9 10^9 109 + 7取模的结果。
示例输入
5 2
1 2 3 4 5
输出
65
说明
第一次操作后,数组变为 [1, 2, 12, 1, 5]
第二次操作,数组变为 [1, 2, 60, 1, 1]
题解
大顶堆解:
import java.util.PriorityQueue;
import java.util.Scanner;
//不知道能不能过
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int k = in.nextInt();
//构造大顶堆
PriorityQueue<Integer> pq = new PriorityQueue<>((o1, o2) -> o2 - o1);
for (int i = 0; i < n; i++) {
pq.offer(in.nextInt());
}
//System.out.println(pq);
int mod = ((int) Math.pow(10, 9) + 7);
int sum = 0;
for (int i = 0; i < k; i++) {
//找前俩最大的,并弹出
int x = pq.poll();
int y = pq.poll();
pq.offer(1);
pq.offer((x * y) % mod);
}
for (int i : pq) {
sum += i % mod;
}
System.out.println(sum);
}
}
原地在数组操作
import java.util.Arrays;
import java.util.Scanner;
//没过,无考虑溢出取模
public class TwoSolution {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int k = in.nextInt();
int[] a = new int[n];
for (int i = 0; i < n; ++i) {
a[i] = in.nextInt();
}
Arrays.sort(a);
int maxIndex = n - 1;
for (int i = 0; i < k && maxIndex > 0; i++) {
//取最大和次大
int max = a[maxIndex];
int max_next = a[maxIndex - 1];
//最大变为1,次大变为二者乘积
a[maxIndex] = 1;
a[maxIndex - 1] = max * max_next;
maxIndex--;
}
System.out.println(Arrays.stream(a).sum());
}
}
小美的数组重排
小美有两个长度为 n 的数组 a 和 b。
小美想知道,能不能通过重排 a 数组使得对于任意 1 <= i <= n,1 <=
a
i
a_i
ai +
b
i
b_i
bi <= m?
将会有 q 次询问。
输入描述
第一行一个整数 q(1 <= q <=30)。表示询问次数。
对于每一个询问:
第一行输入两个整数 n,m (1<=n,m<=500)
第二行输入 n个整数
a
i
a_i
ai(-500<=
a
i
a_i
ai<=500)。
第三行输入 n 个整数 b i b_i bi(-500<= b i b_i bi<=500)。
输出描述
q 行,每行输出一个字符串,如果能通过重排满足条件则输出"Yes"(不含引号),否则输出"No"。
示例输入
2
5 3
-1 -2 3 4 5
-1 3 4 2 5
5 6
-1 -2 3 4 5
-1 3 4 2 5
输出
No
Yes
说明
对于第一个用例,无论怎么重排都不满足条件。
对于第二个用例,将数组 a 重排为 [5,3,-2,4,-1] 时满足条件。
题解
对于数组 a 的最小值,如果跟数组 b 的最大值进行合并,假设结果不满足,那就肯定是不可能的了,否则可以考虑 次小和次大进行分配,以此类推,只需要将 a数组正向排,b数组逆向排
import java.util.Arrays;
import java.util.Scanner;
public class TwoSolution {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int q = in.nextInt();
//q组
for (int i = 0; i < q; i++) {
int n = in.nextInt();
int m = in.nextInt();
int[] a = new int[n];
int[] b = new int[n];
for(int j=0;j<n;j++){
a[j]=in.nextInt();
}
for(int j=0;j<n;j++){
b[j]=in.nextInt();
}
//a正序,b逆序
Arrays.sort(a);
b = Arrays.stream(b).boxed().sorted((o1, o2) -> o2 - o1).mapToInt(p -> p).toArray();
boolean flag = func(n, m, a, b);
if (flag) {
System.out.println("Yes");
} else {
System.out.println("No");
}
}
}
public static boolean func(int n, int m, int[] a, int[] b) {
for (int i = 0; i < n; i++) {
if (a[i] + b[i] >= 1 && a[i] + b[i] <= m) {
continue;
} else {
return false;
}
}
return true;
}
}
平均数为k的最长连续子数组
给定 n 个正整数组成的数组,求平均数正好等于 k 的最长连续子数组的长度。
输入描述
第一行输入两个正整数 n 和 k,用空格隔开。
第二行输入 n 个正整数
a
i
a_i
ai,用来表示数组。
1 <= n<= 200000
1<=k ,
a
i
a_i
ai <=
1
0
9
10^9
109
输出描述
如果不存在任何一个连续子数组的平均数等于 k,则输出 -1。
否则输出平均数正好等于k的最长连续子数组的长度。
示例输入
5 2
1 3 2 4 1
输出
3
说明
取前三个数即可,平均数为2。
题解
暴力
//暴力过不了
public class FiveSolution {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int k = in.nextInt();
int[] nums = new int[n];
for (int i = 0; i < n; i++) {
nums[i] = in.nextInt();
}
int sum = 0;
int result = 0;
for (int i = 0; i < n; i++) {
sum = nums[i];
for (int j = i + 1; j < n; j++) {
sum += nums[j];
if (sum == k * (j - i + 1)) {
result = Math.max(result, j - i + 1);
}
}
}
//暴力做剪枝
/* for (int i = 0; i < n - result; i++) {
sum = nums[i];
for (int j = i + 1; j < n; j++) {
sum += nums[j];
if (sum == k * (j - i + 1)) {
result = Math.max(result, j - i + 1);
}
}
}*/
System.out.println(result);
}
}
一个高手的不太明白的做法
public class FiveSolution {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int k = in.nextInt();
int[] a = new int[n];
for (int i = 0; i < n; i++) {
a[i] = in.nextInt() - k;
}
/*for (int i : a) {
System.out.print(i + " ");
}
System.out.println();*/
int res = 0;
//记录和过的值第一次出现的地方
Map<Integer, Integer> map = new LinkedHashMap<>();
map.put(0, -1);
int sum = 0;
for (int i = 0; i < n; i++) {
sum += a[i];
//当前累加到的值在map里有出现过,说明 i-map.get(sum) 就是一个等于0的子串的长度
if (map.containsKey(sum)) {
res = Math.max(res, i - map.get(sum));
}
else {
map.put(sum, i);
}
//System.out.println("现在的i是:" + i + " sum是:" + sum + " res是:" + res + " map为:" + map);
}
//System.out.println("最终的map:" + map);
System.out.println(res);
}
}