【题目描述】

小N,小A,小T又大了一岁了。

现在,他们已经是高二年级的学生了。众所周知,高二的小朋友是要进行文理科分班考试的,这样子的话,三个好朋友说不定就会不分在一个班。

于是三个人决定,都考平均分。。。。。。

当然这不是我们关心的问题。

年级主任Qian,表示分班真的是很头痛。

校长XXY给Qian的分班条件是这样子。

首先由M个学生,分数从高到低已经排序好了。

其次要分成至多N个班。

每个班必须要有至少A个至多B个小朋友。

一个班的学生,他们的分数必须是连在一起的。也就是说,如果第3个小朋友和第5个小朋友在一间教室,第4个小朋友也必须和他们在一起。

最操蛋的是。。。XXY还给出了一个评定分班好不好的标准。

每个学生有一个不知道啥的敏感指数,X[i],1<=i<=M。并且,有一个变量Average =。为了方便计算,Average取下整,注意是先加起来再除,不是每次除再加。

每个教室有一个舒适程度G[i]。而g[i]表示的是第i个小朋友在哪个教室。

现在XXY要求最小化评价指数=∑(每个同学敏感指数-Average)^2 * 该同学分到班级的舒适度Gi

【输入格式】

本题目有多组数据。第一行有一个整数case(<=10),表示有case组数据。

接下来对于每组数据的第一行有4个正整数,依次是M,N,A,B。

第二行有M个正整数,用空格隔开,分别是X[1],X[2] -----X[M]。

第三行有N个正整数,用空格隔开,分别是G[1],G[2] -----G[N]。

【输出格式】

对于每组数据,要输出三个正整数,以空格隔开,不同数据之间要换行。

三个正整数分别为sigma,class,last。分别表示最小的评价指数。在评价指数最小的情况下,安排的教室的最小数目。在评价指数,安排教师数目最小的情况下,最后一个教室的人数的最小数目。

【输入输出样例】

divide.in

divide.out

1

10 3 1 4

16 11 12 13 10 15 16 17 18 14

4 5 1

186 3 4

【样例解释】

前4个,后4个,中间2个。

【数据规模】

编号

M

N

A B

X

G

1

5

1

1<=A<=B<=M

1<=X[i]<=10^5

-1000<=G[i]<=1000

2

<=10

<=3

3

<=100

<=10

4

<=1000

<=50

5

<=10000

<=200

0<=G[i]<=1000

6

7

8

-1000<=G[i]<=1000

9

10

【题目分析】

设f[i,j]表示将前j个小朋友分到前i个班中的最小评价指数,易写出状态转移方程:

f[i,j] = min {f[i-1,k]+(sum[j]-sum[k])*G[i]} 其中A≤j-k≤ B

sum[i] = ∑(x[i]-Ave)^2

但现在的状态数为10000×200,转移复杂度为O(n),显然会TLE。

将转移方程整理一下:

f[i,j] = min {f[i-1,k]-sum[k]*G[i]}+sum[j]*G[i]

其中j-B≤k≤j-A,i*A<=j<=min(m,i*B)

很明显可用单调队列进行优化

Ans=min{f[i,m]}(1<=i<=n)

Room=i;

Student:  for(i=m-b;i<=m-a;i++)//枚举room-1班结束位置

if(f[room-1,i]+G[room]*(sum[m]-sum[i])==Ans)

Stu=m-i;

故可维护一个单调递增队列,每次转移之前将新的可选状态从队列尾插入,且把比其大的都pop出,同时保证队列头的元素在可选范围之内。这样每次转移就可以只取队列头的元素,将转移复杂度降为O(1)。总的时间复杂度为O(n*k),空间复杂度为O(n)。

  1. #include<stdio.h>
  2. #include<string.h>
  3. #define RG register
  4. #define ll long long
  5. const long long oo = 1LL << 60;
  6. #define min(a, b) ((a) < (b) ? (a) : (b))
  7. void read(RG int &x)
  8. {
  9. RG int c = getchar(), f = 1;
  10. for(; c < '0' || c > '9'; c = getchar())
  11. if(c == '-') f = -1;
  12. for(x = 0; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0';
  13. x *= f;
  14. }
  15. int T, m, n, A, B, room, stu;
  16. ll X[10003], G[203], Aver, f[203][10003], ans;
  17. struct Que
  18. {
  19. int head, tail, ck[10000 + 3];
  20. void fresh() {head = 1; tail = 0;}
  21. void pop_top(RG int p)
  22. { while(head <= tail && ck[head] + B < p) ++head;}
  23. void push(RG int i, RG ll k, RG int p)
  24. {
  25. while(head <= tail && f[i - 1][ck[tail]] - G[i] * X[ck[tail]] > k) --tail;
  26. ck[++tail] = p;
  27. }
  28. int front() { return ck[head];}
  29. }Q;
  30. int main()
  31. {
  32. freopen("divide.in", "r", stdin);
  33. freopen("divide.out", "w", stdout);
  34. for(read(T); T; --T)
  35. {
  36. read(m), read(n), read(A), read(B);
  37. Aver = 0;
  38. for(RG int i = 1, x; i <= m; ++i) read(x), X[i] = x, Aver += X[i];
  39. Aver /= (ll)m;
  40. for(RG int i = 1; i <= m; ++i) X[i] -= Aver, X[i] *= X[i], X[i] += X[i - 1];
  41. for(RG int i = 1, g; i <= n; ++i) read(g), G[i] = g;
  42. for(RG int i = 0; i <= n; ++i)
  43. for(RG int j = 0; j <= m; ++j) f[i][j] = oo;
  44. f[0][0] = 0;
  45. for(RG int i = 1; i <= n; ++i)
  46. {
  47. Q.fresh();
  48. for(RG int j = i * A; j <= min(i * B, m); ++j)
  49. {
  50. Q.pop_top(j);
  51. Q.push(i, f[i - 1][j - A] - G[i] * X[j - A], j - A);
  52. f[i][j] = f[i - 1][Q.front()] + G[i] * (X[j] - X[Q.front()]);
  53. }
  54. }
  55. ans = oo;
  56. for(RG int i = 1; i <= n; ++i)
  57. if(ans > f[i][m]) ans = f[i][m], room = i;
  58. if(room == 1) stu = m;
  59. else
  60. for(RG int j = m - B; j <= m - A; ++j)
  61. if(f[room - 1][j] + G[room] * (X[m] - X[j]) == ans) stu = m - j;
  62. printf("%I64d %d %d\n", ans, room, stu);
  63. }
  64. fclose(stdin);
  65. fclose(stdout);
  66. return 0;
  67. }

  

[第一波模拟\day1\T2]{分班}(divide.cpp)的更多相关文章

  1. [第一波模拟\day3\T2]{独立集}(bubble.cpp)

    [问题描述] 有一天,一个名叫顺旺基的程序员从石头里诞生了.又有一天,他学会了冒泡排序和独立集.在一个图里,独立集就是一个点集,满足任意两个点之间没有边.于是他就想把这两个东西结合在一起.众所周知,独 ...

  2. [第一波模拟\day2\T1] {病毒分裂}(split.cpp)

    [题目描述] A 学校的实验室新研制出了一种十分厉害的病毒.由于这种病毒太难以人工制造了,所以专家们在一开始只做出了一个这样的病毒.这个病毒被植入了特殊的微型芯片,使其可以具有一些可编程的特殊性能.最 ...

  3. 【NOIP2016 Day1 T2】天天爱跑步

    题目传送门:https://www.luogu.org/problemnew/show/P1600 感觉这两天在处理边界问题上有点神志不清......为了从80的暴力变成100,花了整整一个下午+一个 ...

  4. 【2018.06.26NOIP模拟】T2号码bachelor 【数位DP】*

    [2018.06.26NOIP模拟]T2号码bachelor 题目描述 Mike 正在在忙碌地发着各种各样的的短信.旁边的同学 Tom 注意到,Mike 发出短信的接收方手机号码似乎都满足着特别的性质 ...

  5. 模拟赛T2 交换 解题报告

    模拟赛T2 交换 解题报告 题目大意: 给定一个序列和若干个区间,每次从区间中选择两个数修改使字典序最小. \(n,m\) 同阶 \(10^6\) 2.1 算法 1 按照题意模拟,枚举交换位置并比较. ...

  6. codevs 4511 信息传递(NOIP2015 day1 T2)

    4511 信息传递 NOIP2015 day1 T2 时间限制: 1 s 空间限制: 128000 KB 传送门 题目描述 Description 有个同学(编号为 1 到)正在玩一个信息传递的游戏. ...

  7. 3728 联合权值[NOIP 2014 Day1 T2]

    来源:NOIP2014 Day1 T2 OJ链接: http://codevs.cn/problem/3728/ https://www.luogu.org/problemnew/show/P1351 ...

  8. [NOIP2016 DAY1 T2]天天爱跑步-[差分+线段树合并][解题报告]

    [NOIP2016 DAY1 T2]天天爱跑步 题面: B[NOIP2016 DAY1]天天爱跑步 时间限制 : - MS 空间限制 : 565536 KB 评测说明 : 2s Description ...

  9. 【NOIP2016】DAY1 T2 天天爱跑步

    [NOIP2016]DAY1 T2 天天爱跑步 Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要玩家每天按时 ...

随机推荐

  1. deque双向队列

    对于双向队列,与队列queue以及vector容器的区别就在于,名字不同,也就是它是双向的,可以从头开始操作,也可以从末尾开始操作. 双向队列的常用方法跟队列queue差不多: 头文件: #inclu ...

  2. jvm 实战

    https://blog.csdn.net/neutrojan/article/details/50532590# 1.ps -ef |grep java 找出最耗性能的JAVA进程2.top -Hp ...

  3. 记忆化搜索(DFS+DP) URAL 1223 Chernobyl’ Eagle on a Roof

    题目传送门 /* 记忆化搜索(DFS+DP):dp[x][y] 表示x个蛋,在y楼扔后所需要的实验次数 ans = min (ans, max (dp[x][y-i], dp[x-1][i-1]) + ...

  4. RCC 2014 Warmup (Div. 1)

    A 暴力 #include <iostream> #include<cstdio> #include<cstring> #include<algorithm& ...

  5. C#基础学习5

    数组集合

  6. PHP的知识点总结1

    PHP 基础知识总结 2015-06-03 分类: 编程技术   PHP 代表 PHP: Hypertext Preprocessor PHP 文件可包含文本.HTML.JavaScript代码和 P ...

  7. C#中构造函数和析构函数区别

    把对象的初始化工作放在构造函数中,把清除工作放在析构函数中.当对象被创建时,构造函数被自动执行.当对象消亡时,析构函数被自动执行.这样就不用担心忘记对象的初始化和清除工作. 析构函数是由垃圾回收器控制 ...

  8. react ant design路由配置

    最初的时候,只使用了antd中的menu,header和footer都是自己写的组件,在写路由时,总是报如下错误: 相关的路由配置如下: 在网上查的说是组件未暴露出去或者是return 这一行必须有个 ...

  9. android studio 新建文件出错

  10. Ubuntu 创建docker 容器 系列一

    docker 官网安装地址:https://docs.docker.com/install/linux/docker-ce/ubuntu/ 1.Ubuntu的版本要在12.04 LTS 以上,使用un ...