• [HEOI2015]小L的白日梦


    更好的阅读体验

    本文参考了yyb大神的题解,并且加入了一些自己的看法

    三个性质都可以和暴力拍上,所以应该是正确的

    性质1:一定存在最优解每天不高兴的概率是单调不增的

    看着比较显然

    证明也比较容易,首先按不高兴概率单调不增把每个项目排序,说人话就是令(a_ige a_{i+1})

    根据期望线性性,当前期望为(E=sumlimits_{i=1}^n(1-a_{i-1})a_i)

    考虑类似贪心的临项交换法,假设两数在原数列位置是(i,j),且(i<j),交换,令原式与交换后式子做差

    [Delta=(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})-(1-a_i)a_{j+1}\ ]

    化简式子

    [=(a_i-a_j)(a_{j-1}-a_{i-1})+(a_{i+1}-a_{j+1})(a_j-a_i)\ =(a_i-a_j)(a_{j-1}+a_{j+1}-a_{i-1}-a_{i+1}) ]

    因为有(a_{i-1}>a_i>a_{i+1}>a_{j-1}>a_j>a_{j+1})

    所以有(Delta<0),所以序列单调不增期望最小

    性质2:选择的一定是排序后的一段前缀和一段后缀

    不妨设(i<j<k<l)表示四个项目,它们不高兴概率为(a>b>c>d)

    假设我们选择的原情况是选了([1,i],j,[l,n]),期望是((1-a)b+(1-b)d)

    新情况是选了([1,i],k,[l,n]),期望是((1-a)c+(1-c)d)

    新情况优于原情况时,满足((1-a)b+(1-b)d>(1-a)c+(1-c)d)

    解得(a+d>1),也就是说,中间点会靠到后缀上,反之靠到前缀上

    综上,前缀和后缀中间不会有点被选中

    先用这两个性质做,我们可以预处理前缀和后缀最大贡献,枚举前缀端点,对于所有后缀而言,找一个最大的贡献即可,这样可以做(1e6),但是做不了(1e9)

    性质3:每个东西要么选一个,要么全选,除了这两种情况的其它情况最多只出现一次

    首先没选完整的最多只可能有两块,前缀的最后和后缀的最前

    考虑后缀最靠前的一段多出来了若干个,把一个 后缀的多余 给 前缀最后一个,期望值减少量是(Delta),更优,我们不断减少后缀,直到后缀第一个块只剩一个点,再次削减肯定代价不再是(Delta),所以不能转移了

    (根据上面式子可以比较容易得出)

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long lng;
    typedef long double ldb;
    struct data {
    	int cnt;
    	ldb val;
    	inline data() {};
    	inline data(int a, ldb b)
    		: cnt(a), val(b) {};
    	inline void read() {
    		static int a, b;
    		scanf("%d/%d", &a, &b);
    		val = (ldb)a / b;
    		scanf("%d", &cnt);
    	}
    } A[150000], B[350000];
    inline bool operator < (const data &a, const data &b) {
    	return a.val > b.val;
    }
    int n, m, cas, tot;
    inline ldb calc() {
    	ldb ret = 1E18, sum = 0;
    	lng now = 1, rem = m;
    	for (int i = n; i; --i)
    		sum += (B[i].cnt - 1) * B[i].val * (1 - B[i].val) + (1 - B[i].val) * B[i + 1].val, rem -= B[i].cnt;
    	for (int i = 1; i <= n; ++i ) {
    		rem -= B[i].cnt;
    		while (now <= n && rem <= 0)
    			sum -= (B[now].cnt - 1) * B[now].val * (1 - B[now].val) + (1 - B[now].val) * B[now + 1].val, rem += B[now++].cnt;
    		if (rem <= 0)break;
    		sum += (B[i].cnt - 1) * B[i].val * (1 - B[i].val) + (1 - B[i - 1].val) * B[i].val;
    		ret = min(ret, sum + (rem - 1) * B[now - 1].val * (1 - B[now - 1].val) + (1 - B[now - 1].val) * B[now].val + (1 - B[i].val) * B[now - 1].val);
    	}
    	rem = m, sum = 0;
    	for (int i = 1; i <= n; ++i) {
    		int mn = min(rem, (lng)B[i].cnt);
    		if(!mn)break;
    		else rem -= mn, sum += (mn - 1) * B[i].val * (1 - B[i].val) + (1 - B[i - 1].val) * B[i].val;
    	}
    	return ret = min(ret, sum);
    }
    signed main() {
    	for (scanf("%d", &cas); cas--; ) {
    		scanf("%d%d", &n, &m);
    		for (int i = 1; i <= n; ++i) {
    			A[i].read();
    			if (!A[i].cnt)--i, --n;
    		}
    		sort(A + 1, A + n + 1);
    		tot = 0;
    		for (int i = 1; i <= n; ++i) {
    			B[++tot] = data(1, A[i].val);
    			if (--A[i].cnt) {
    				if (A[i].cnt > 1)
    					B[++tot] = data(A[i].cnt - 1, A[i].val);
    				B[++tot] = data(1, A[i].val);
    			}
    		}
    		B[0].val = 1, B[(n = tot) + 1].val = 0;
    		ldb ans = calc();
    		for (int i = 1; i <= n; ++i)
    			if (i < n + 1 - i)swap(B[i], B[n + 1 - i]);
    		for (int i = 1; i <= n; ++i)B[i].val = 1 - B[i].val;
    		ans = min(ans, calc());
    		printf("%.6lf
    ", (double)fabs(ans));
    	}
    }
    
  • 相关阅读:
    小议IE8下的KB927917错误
    一道面试附加题的另类求解
    Win7和WinXP共享的设置问题二则——共享打印机和FTP
    PS网页设计教程I——在Photoshop中创建时尚多彩的wordpress布局
    转自51CTO的帖子——宅男程序员给老婆的计算机课程
    Javascript笔记:jQuery源码分析以及从jQuery对象创建的角度理解extend方法的原理
    Javascript笔记:(实践篇)从jQuery插件技术说起深入分析extend方法(中篇)
    体验版:在百度搜索"2012世界末日"所展现的地震效果的源代码(嵌入到我的博客里)
    Javascript笔记:(实践篇)从jQuery插件技术说起(上篇)
    javascript笔记:自己写一个jqgrid框架(二)
  • 原文地址:https://www.cnblogs.com/shikeyu/p/13874512.html
Copyright © 2020-2023  润新知