BZOJ 4030: [HEOI2015]小L的白日梦
4030: [HEOI2015]小L的白日梦
Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 172 Solved: 39
[Submit][Status][Discuss]
Description
在某一天,你有了一个女性朋友。
Input
第一行有一个非负整数t,表示一共有t组数据。
Output
一共t行,对于每组数据输出使她感到失落的最小期望次数,四舍五入保留6位小数。
Sample Input
1 2
0/1 3
1 2
1/1 3
1 2
1/2 3
Sample Output
0.000000
0.250000
【样例说明】
考虑第三组数据,因为只有一个项目所以只好每天都安排这个。
在第一天之前她总是不高兴的,一共有:
第一天不高兴,第二天也不高兴、
第一天高兴,第二天不高兴、
第一天不高兴,第二天高兴、
第一天不高兴,第二天也不高兴,
这四种情况,又因为每天的项目让她高兴或者是不高兴的概率都是0.5,因此这四种情况是等概率发生的。
只有在第二种情况下,她会感到失落一次。
因此答案是(1*1+0*3)/4=0.25.
HINT
对于100%的数据,n<=105,k<=109,数据组数不会太多,大概不超过10组,数据保证分数有意义并且∑c[i]>=k。
Source
这种网上没有题解的题,必须要写一发骗骗访问量哈~~~
我上午做这道题的时候,网上没有专门的题解,只有jiry前辈的一篇HEOI2015系列题解可做参考,所以我就无耻地抄代码啦~~~
先转一下jiry的题解内容——
【D2T1】小L的白日梦
这题我在网上找不到题解..但是为了访问量我也是只好硬上了...我的算法建立在以下假设之上:
1.一定存在最优解每一天不高兴的概率是单调不增的。
2.一定存在最优解它选取的项目是所有项目按照不高兴的概率排序后的前缀一段加上后缀一段。
3.每一次选取的项目种类只有三种可能的情况:选了1个,全部选完,其他。且处于第三种状态的至多一个。
不要问我是怎么知道这三个假设的..我连最基本的假设1都不会证明..这些全部都是在各种暴力求证之后得到了..这A的实在是6的不行..
知道了这些假设就很简单了..假设第三种状态的是取在后缀中的,那么枚举选取前缀最右端的位置,后缀最左端的位置单调不增,扫一下就好了,反过来也是一样。
我看了看这三个假设,如果是正确的话那么jiry的做法确实很棒棒,但是我只能证明第一个,好菜啊。下午Monster__Yi来嘲讽我了,“这么水的题,你都不会证明?还考什么NOI,HEOI你就可以滚粗了!” 唔唔唔,宝宝心里苦啊……
然后在小天天(Monster_Yi)的帮助下,我(ta)证明了另外两个性质,所以记录一下,趁着他还没写赶紧骗访问量,23333
性质1:一定存在最优解每一天不高兴的概率是单调不增的
这个性质最显然,证明方法就是列个式子,用$a_i$表示排序后第i个项目的不高兴概率,那么当前的期望值就是
$$P=(1-a_0)a_1+(1-a_1)a_2+(1-a_2)a_3+...+(1-a_{n-1})a_n$$
然后考虑交换两个项,$a_i$和$a_j$,现在的期望值变成了
$$P'=(1-a_0)a_1+...+(1-a_{i-1})a_j+(1-a_j)a_{i+1}+...+(1-a_{j-1})a_i+(1-a_i)a_{j+1}$$
根据$a_{i-1} \gt a_i \gt a_{i+1} \gt a_{j-1} \gt a_j \gt a_{j+1}$,
我们有
$$P-P'=(1-a_{i-1})a_i+(1-a_i)a_{i+1}+(1-a_{j-1})a_j+(1-a_j)a_{j+1}-(1-a_{i-1})a_j-(1-a_j)a_{i+1}-(1-a_{j-1})a_i-(1-a_i)a_{j+1}=(1-a_{i-1})(a_i-a_j)-a_{i+1}(a_i-a_j)-(1-a_{j-1})(a_i-a_j)+a_{j+1}(a_i-a_j)=(a_i-a_j)(-a_{i+1}-a_{i+1}+a_{j-1}+a_{j+1}) \lt 0$$
所以$P \lt P'$,即按照不高兴概率递减的顺序排列,期望更优。
性质2:一定存在最优解它选取的项目是所有项目按照不高兴的概率排序后的前缀一段加上后缀一段
这个性质也是列式子证明的。我们不妨设$A \lt B \lt C \lt D$,代表四个项目(按照不高兴概率递减的顺序排列),我们用$a,b,c,d$表示其不高兴概率,有$a\gt b\gt c\gt d$。
我们设原情况是我们从整个序列中选取了三段——[1,A],B,[D,N]。
我们设新情况是我们从整个序列中选取了三段——[1,A],C,[D,N]。
原情况的期望是$(1-a)b+(1-b)d$。
新情况的期望是$(1-a)c+(1-c)d$。
当新情况优于原情况,必然有$(1-a)b+(1-b)d>(1-a)c+(1-c)d$
解得$a+d>1$,这个就说,当$a+d>1$时,中间的点会往右靠,直到靠到后缀上;反之,中间的点会往前靠,直到靠到前缀上。所以,前缀和后缀中间不会有点被选中。
性质3:每一次选取的项目种类只有三种可能的情况:选了1个,全部选完,其他,且处于第三种状态的至多一个
前两个性质我们都是把所有项目拆成$c_i$个单独的项目考虑的,并且已经可以解决$\sum c_i \leq 10^6$时的问题了。现在我们考虑把相同项目看成一个连续的块,会有什么新的性质。
可喜可贺的是,这个性质不用列式子了,随便一想就能发现。
如果我们当前前缀的最后一个块(也就是最后一种项目)只选取了一个点,后缀的最前一个块选取了若干个点。
然后我们发现把后缀的一个名额送给前缀的最后一个块,会使期望值减少$delta$,使期望值变优。那么,我们可以说,在后缀的最后一个块露出尾巴(也就是被削减得只剩一个点)之前,我们每把一个后缀名额送给前缀,都会使得期望减少$delta$。所以我们定然会把后缀不断减少,直到其最前一个块只剩一个点为止,此时再削减最后一个块,产生的代价将不再是$delta$,所以不能继续无脑转移名额了。
可见,前缀和后缀的最后(前)一个块在某些情况只会选一个点,但绝不会同时选若干个点,都不是1而且都没有全选。
代码还是抄的jiry前辈的,毕竟我的代码功底可是非常差的。
#include <bits/stdc++.h>
using namespace std;
typedef long long lng;
typedef long double ldb;
struct data {
int cnt; ldb val;
inline data(void) {};
inline data(int a, ldb b)
: cnt(a), val(b) {};
inline void read(void) {
static int a, b;
scanf("%d/%d", &a, &b);
val = (ldb)a / b;
scanf("%d", &cnt);
}
}A[], B[];
inline bool operator < (const data &a, const data &b) {
return a.val > b.val;
}
int n, m, cas, tot;
inline ldb calc(void) {
ldb ret = 1E18, sum = ;
lng now = , rem = m;
for (int i = n; i; --i)
sum += (B[i].cnt - ) * B[i].val * ( - B[i].val) + ( - B[i].val) * B[i + ].val, rem -= B[i].cnt;
for (int i = ; i <= n; ++i ) {
rem -= B[i].cnt;
while (now <= n && rem <= )
sum -= (B[now].cnt - ) * B[now].val * ( - B[now].val) + ( - B[now].val) * B[now + ].val, rem += B[now++].cnt;
if (rem <= )break;
sum += (B[i].cnt - ) * B[i].val * ( - B[i].val) + ( - B[i - ].val) * B[i].val;
ret = min(ret, sum + (rem - ) * B[now - ].val * ( - B[now - ].val) + ( - B[now - ].val) * B[now].val + ( - B[i].val) * B[now - ].val);
}
rem = m, sum = ;
for (int i = ; i <= n; ++i) {
int mn = min(rem, (lng)B[i].cnt);
if(!mn)break; else rem -= mn, sum += (mn - ) * B[i].val * ( - B[i].val) + ( - B[i - ].val) * B[i].val;
}
return ret = min(ret, sum);
}
signed main(void) {
for (scanf("%d", &cas); cas--; ) {
scanf("%d%d", &n, &m);
for (int i = ; i <= n; ++i) {
A[i].read(); if (!A[i].cnt)--i, --n;
}
sort(A + , A + n + ); tot = ;
for (int i = ; i <= n; ++i) {
B[++tot] = data(, A[i].val);
if (--A[i].cnt) {
if (A[i].cnt > )
B[++tot] = data(A[i].cnt - , A[i].val);
B[++tot] = data(, A[i].val);
}
}
B[].val = , B[(n = tot) + ].val = ;
ldb ans = calc();
for (int i = ; i <= n; ++i)
if (i < n + - i)swap(B[i], B[n + - i]);
for (int i = ; i <= n; ++i)B[i].val = - B[i].val;
ans = min(ans, calc());
printf("%.6lf\n", (double)fabs(ans));
}
}
@Author: YouSiki
BZOJ 4030: [HEOI2015]小L的白日梦的更多相关文章
- 【BZOJ4030】[HEOI2015]小L的白日梦
[BZOJ4030][HEOI2015]小L的白日梦 题面 BZOJ 洛谷 题解 要求的是最小的不开心连续段的期望. 然后发现自己就不会做了. 然后就可以来抄题解啦. 首先来猜性质: 第一个,一定是按 ...
- HEOI2015小L的白日梦
题面链接 洛咕 sol 为什么网上面只有神仙题解啊!!! 引起我这种蒟蒻不适QAQ. 性质证明留给巨佬 然后我只贴性质了QwQ. 1.一定存在最优解每一天不高兴的概率是单调不增的. 2.一定存在最优解 ...
- P4110 [HEOI2015]小L的白日梦
传送门 题解 //minamoto #include<bits/stdc++.h> using namespace std; typedef long long ll; typedef l ...
- bzoj 4031: [HEOI2015]小Z的房间 轮廓线dp
4031: [HEOI2015]小Z的房间 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 98 Solved: 29[Submit][Status] ...
- BZOJ 4031: [HEOI2015]小Z的房间 高斯消元 MartixTree定理 辗转相除法
4031: [HEOI2015]小Z的房间 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4031 Description 你突然有了一个 ...
- bzoj4030【HEOI2015】小L的白日梦
题意:http://www.lydsy.com/JudgeOnline/problem.php?id=4030 sol :orz Yousiki http://www.cnblogs.com/you ...
- 【刷题】BZOJ 4031 [HEOI2015]小Z的房间
Description 你突然有了一个大房子,房子里面有一些房间.事实上,你的房子可以看做是一个包含n*m个格子的格状矩形,每个格子是一个房间或者是一个柱子.在一开始的时候,相邻的格子之间都有墙隔着. ...
- BZOJ 4031: [HEOI2015]小Z的房间 Matrix-Tree定理
题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=4031 题解: Matrix-tree定理解决生成树计数问题,其中用到高斯消元法求上三角矩 ...
- BZOJ:4031: [HEOI2015]小Z的房间
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1103 Solved: 536[Submit][Status][Discuss] Descripti ...
随机推荐
- 等价路由在路由器和CE交换机上默认的行为是不同的,路由器总是走第一个下一跳,CE交换机是逐包。
结论: 1.在eNSP中实验,路由器和CE交换机对于等价路由的默认转发行为是不同的, 路由器:默认是基于流的转发形态,更准确的来讲,ping两个不同的下一跳,都是走等价路由的第一个路由,不走第二条路由 ...
- WPF:DropShadowEffect 生效
1.BorderThickness = “XX”,xx可以当作阴影四周的宽度 2.BorderBrush="Transparent"
- 设计模式系列之单例模式(Singleton Pattern)
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式.这种模式涉及到一个单一的类,该类负责创建自己的对象 ...
- gitbook 入门教程之导出电子书
gitbook 既可以将源码文件单独输出,也可以仅输出单个文件,常见的导出电子书格式主要有三种(ePub, Mobi, PDF),而这三种格式都依赖于系统本身提供的 ebook-convert 工具. ...
- 【Linux】【Java】CentOS7安装最新版Java1.8.191运行开发环境
1.前言 本来在写[Linux][Apatch Tomcat]安装与运行.都快写完了. 结果...我忘记安装 Java 环境 然后...新开了博客编辑页面. 最后...我的那个没了...没了...真的 ...
- 初使用maven遇到各种问题记录
Cannot change version of project facet Dynamic Web Module to 2.5? 解决办法:将web.xml配置文件中的<web-app ver ...
- Yii2.0调用sql server存储过程并获取返回值
1.首先展示创建sql server存储过程的语句,创建一个简单的存储过程,测试用. SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE P ...
- 建立第一个SpringBoot小列子(碰到的错误)
当加入@SpringBootApplication注解时,无法得到解析 错误提示:SpringBootApplication cannot be resolved to a type 错误原因是因为s ...
- mybatis使用oracle的sequence
oracle数据库创建SEQUENCE CREATE SEQUENCE SEQ_COM_MASTER START INCREMENT MINVALUE MAXVALUE NOCYCLE CACHE ; ...
- Python中的一些小技巧
1.Boolean值可以当做一个数值 a = [5,6,7,8,9] print(a[True]) #prints 6 print(a[False]) #prints 5 2.两种方法实现 a = 1 ...