第一题:
n个农场,第i个农场有a[i]只鸡,每天每个农场都会增加k只鸡。每晚农场主都会选择鸡最多的农场,将该农场鸡的个数除以2下取整,在m天后剩下多少只鸡?
输入:
3 3 100 100 200 400
输出:
925
解释:
(100 200 400)->(200 300 250)->(300 200 350)->(400 300 225) (400+100)/2=250 (300+100)/2=200 (350+100)/2=225
400+300+225=925
第二题:
序列arr={a1,a2,...,an}的所有连续子序列最大值的期望是多少?【连续子序列为{ai,ai+1,...,aj-1,aj},输出取六位有效数字】
输入:
3 //表示序列的个数
1 2 3 //表示序列的值
输出
2.333333
解释:
连续子序列:
{1,2,3}->{1},{2},{3},{1,2},{2,3},{1,2,3} 最大值: {1}:1 {2}:2 {3}:3 {1,2}:2 {2,3}:3 {1,2,3}:3 将最大值求和取平均值:(1+2+3+2+3+3)/6=2.333333
解答:
第一题:
public class Test1 { /** *思路: * 同步增加就相当于不增加,到最后一起增加 *步骤: * 1.每次取优先队列最大值max,然后减去(需要减去的值也就是)当前为i天则(i*k+max)/2上取整,最后将值放回优先队列中 * 2.最终将优先队列中的值全相加再加上同步增加的值(m*n*k) */ //n,m,k,a[i] public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int m = sc.nextInt(); int k = sc.nextInt(); PriorityQueue<Integer> queue = new PriorityQueue<>(n, (o1, o2) -> o2 - o1); for (int i = 0; i < n; i++) { queue.add(sc.nextInt()); } //每次取优先队列最大值max,然后减去(需要减去的值也就是)当前为i天则(i*k+max)/2上取整,最后将值放回优先队列中 for (int i = 1; i <= m; i++) { int tmp = queue.poll(); //获得没有更新的最大值 int num = tmp + i * k; //获得真实的最大值 num -= num / 2; //获得一半的上界 tmp -= num; //(没有更新的最大值)减去(需要减去的真实上界一半的值) queue.add(tmp); } //最终将优先队列中的值全相加再加上同步增加的值(m*n*k) int result = m * n * k + queue.stream().mapToInt(e -> e).sum(); System.out.println(result); } }
第二题:
方法一:动态规划【时间复杂度最差O[n*n]】
import java.util.HashMap; import java.util.Scanner; public class Test2 { //输入:3 //输出:1 2 3 //思路:动态规划 // 使用map保留前n项所有子序列集合的最大值(key)和出现次数(value),在第n+1项时将map中的key与a[n+1]比较 //1.若key比a[n+1]大则计算key与value的乘积,累加到result结果中 //2.若key比a[n+1]小则将key对应的value值加到a[n+1]对应的value值上,并清空原来key对应的值 //3.最终将a[n+1]乘上对应的value,累加到result结果中 public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int[] a = new int[n]; for (int i = 0; i < n; i++) { a[i] = sc.nextInt(); } int all = n * (n + 1) / 2; double result = 0; //保留最大值,以及最大值出现的次数 HashMap<Integer, Integer> maxValue = new HashMap<>(n); for (int i = 0; i < n; i++) { if (maxValue.containsKey(a[i])) { maxValue.put(a[i], maxValue.get(a[i]) + 1); } else { maxValue.put(a[i], 1); } int count = maxValue.get(a[i]); for (Integer key : maxValue.keySet()) { if (key > a[i]) { //之前子序列最大值大于a[i],则子序列最大值不变 result += key * maxValue.get(key); } else if (key < a[i]) { //之前子序列最大值小于a[i],则将原来子序列的值加到a[i]为key的值上,并清空原来子序列值 count += maxValue.get(key); maxValue.put(a[i], count); maxValue.put(key, 0); } } //最后将以a[i]为最大值的子序列个数乘以a[i] result += a[i] * count; } //求期望并调整有效位 result /= all; result = (long) (result * Math.pow(10, 6)) / Math.pow(10, 6); System.out.println(result); } }
方法二:单调栈【时间复杂度最差O(n+n)】
import javafx.util.Pair; import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class Test2 { //输入:3 //输出:1 2 3 //思路:单调栈 public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int all = n * (n + 1) / 2; double result = 0; /** * List<AbstractMap.SimpleEntry<Integer, Integer>> list1 = new ArrayList<>(); * list1.add(new AbstractMap.SimpleEntry<>(1, 1)); * 等价于 * List<Pair<Integer, Integer>> list = new ArrayList<>(); * list.add(new Pair<>(1,1)); */ //单调递减栈 List<Pair<Integer, Integer>> list = new ArrayList<>(); int listSize = list.size(); int listValue = 0; for (int i = 0; i < n; i++) { int num = sc.nextInt(); int count = 1; for (int j = listSize - 1; j >= 0; j--) { if (list.get(j).getKey() > num) { break; } else { count += list.get(j).getValue(); listValue -= list.get(j).getKey() * list.get(j).getValue(); list.remove(j); listSize--; } } list.add(new Pair<>(num, count)); listValue += num * count; result += listValue; listSize++; } //求期望并调整有效位 result /= all; result = (long) (result * Math.pow(10, 6)) / Math.pow(10, 6); System.out.println(result); } }