第一題:
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); } }