题目:
【问题背景】
古语有云:春风得意马蹄疾,一日看尽长安花。
当然在一场考试中所有人都春风得意马蹄疾是不可能的,尤其是碰到一些毒瘤出题人的时候。
【问题描述】
又到了每月一次的月考,又是 xf 老师出题。
上一次 xf 老师出的题太毒瘤了,平均分只有 40 多,同学们都非常不满意,毕竟别的科的平均分都是 80 多。
这次 xf 为了不被同学们寄刀片,想了一个办法:只公布所有考场的平均分的平均分。这样他就可以通过调整考场的分配方式,使得平均分显得高。(每个考场都可以容纳无限人)
每次考试也不是所有同学都参加的,只有学号在 [l,r] 这个区间中的同学会参加。
他想知道对于每次考试,他调整过考场后,所有考场的平均分的平均分的最大值。
当然,同学们也可能会努力学习或整日颓废使成绩发生改变。
【输入格式】
输入的第一行包含一个整数 n。
第二行包含 n 个整数,第 i 个数 vi,表示开始时每个同学的成绩。
第三行包含一个整数 q,表示有 q 次操作。
之后 q 行,每行描述一个操作,第一个数表示操作类型。
如果操作为 1 p x,表示学号为 p 的同学分数变为 x。
如果操作为 2 l r k, 表示把学号在 [l,r] 中的同学分成 k 个考场,求这 k 个考场的平均分的平均分的最大值。
【输出格式】
对于每个 2 操作输出一行,四舍五入保留正好 3 位小数。
【样例输入】
5
5 3 4 2 1
5
2 1 4 3
1 4 8
2 3 5 3
1 2 2
2 1 3 2
【样例输出】
3.833
4.333
4.000
【样例说明】
第一个操作询问学号在 [1, 4] 之间的同学分成 3 个考场的平均分的平均分的最大值,最优策略是:{1}, {2, 4}, {3},平均分是
第二个操作把学号为 4 的同学的分数变为 8。
第三个操作询问学号在 [3, 5] 之间的同学分成 3 个考场的平均分的平均分的最大值,最优策略是:{3}, {4}, {5}。
第四个操作把学号为 2 的同学分数变为 2。
第五个操作询问学号在 [1, 3] 之间的同学分成 2 个考场的平均分的平均分的最大值,最优策略是:{1}, {2 3}。
【评测用例规模与约定】
对于全部评测用列,n ≤ 200000, q ≤ 200000, 任意时刻同学的分数 vi ≤ 109,k ≤ r − l + 1。
评测时将使用 10 个评测用例测试你的程序,每个评测用例的限制如下:
题解:
首先肯定是分析,就是有一组同学这组同学有各自的成绩,然后给你几个操作,操作为1 的话是改变同学的成绩,操作为2的话就是在当前成绩(有可能已经修改过)下计算,把所有学生分为k组求所有组平均分的平均分最大值,就是每一个小组先求平均值,然后求小组的和,再求平均值,则最大的是多少,示例已经有了,5 3 4 2分3组怎么才能保证3组的平均数的和的平均数最大。
我的思路:
我是使用dfs的,全排列把所有的分法遍历一边,一个数组记录每个组的分数和,一个数组记录每个组分了几次,
例如: 一种:记录分数和:14,0,0 记录次数:4,0,0
二种:记录分数和:12,2,0 记录次数:3,1,0
三种:记录分数和:8,6,0 记录次数:2,2,0
用一个max记录遍历所有情况中的最大值(是所有小组的平均值的和的平均值),最后输出max就是一次操作为2 时候的数值了。
后面就没有什么难度了,附上代码: (记得最后处理一下保留的小数)
package _2019_10;
import java.text.DecimalFormat;
import java.util.Scanner;
public class Main {
static int nums[];
static int targetnums[];
int numbers[];
static double max=Integer.MIN_VALUE;
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int n=scanner.nextInt();
nums=new int[n+1];
targetnums=new int[n+1];
for (int i = 1; i <=n; i++) {
nums[i]=scanner.nextInt();
}
int m=scanner.nextInt();
String maxnums[]=new String[m];
int index=0;
for (int i = 0; i < m; i++) {
int step=scanner.nextInt();
if (step==1) {
int num=scanner.nextInt();
int core=scanner.nextInt();
nums[num]=core;
}else if (step==2) {
int num1=scanner.nextInt();
int num2=scanner.nextInt();
int num3=scanner.nextInt();
int numbers[]=new int[num3];
int numbers2[]=new int[num3];
dfs(num1,num2,numbers,numbers2);
maxnums[index]=new DecimalFormat("0.000").format(max).toString();
max=Integer.MIN_VALUE;
index++;
}
}
for (int i = 0; i < index; i++) {
System.out.println(maxnums[i]);
}
}
static void dfs(int num1,int num2,int numbers[],int numbers2[]) {
if (num1>num2) {
double sumnums = 0;
for (int i = 0; i < numbers.length; i++) {
if (numbers2[i]!=0) {
sumnums+=(double)numbers[i]/numbers2[i];
}
}
sumnums=sumnums/numbers.length;
if (sumnums>max) {
max=sumnums;
}else {
return;
}
return;
}
for (int i = 0; i <numbers.length; i++) {
numbers[i]+=nums[num1];
numbers2[i]++;
dfs(num1+1, num2, numbers,numbers2);
numbers[i]-=nums[num1];
numbers2[i]--;
}
}
}
结语:这样写的话数据量大的话绝对会超时,只是骗分操作吧,没有好思路只能骗分了
。