• HEOI2015小L的白日梦


    题面链接

    洛咕

    sol

    为什么网上面只有神仙题解啊!!!

    引起我这种蒟蒻不适QAQ。

    性质证明留给巨佬

    然后我只贴性质了QwQ。

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

    2.一定存在最优解它选取的项目是所有项目按照不高兴的概率排序后的前缀一段加上后缀一段。

    3.每一次选取的项目种类只有三种可能的情况:选了1个,全部选完,其他。且处于第三种状态的至多一个。

    认认真真写的代码

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define gt getchar()
    #define ll long long
    #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
    inline int in()
    {
    	int k=0;char ch=gt;
    	while(ch<'-')ch=gt;
    	while(ch>'-')k=k*10+ch-'0',ch=gt;
    	return k;
    }
    struct node
    {
    	long double val;
    	int cnt;
    	node(){}
    	node(long double _val,int _cnt):val(_val),cnt(_cnt){}
    	inline void read()
    		{
    			int a,b;
    			scanf("%d/%d",&a,&b);
    			val=(long double)a/b;
    			scanf("%d",&cnt);
    		}
    	inline bool operator<(const node &a)const{return val>a.val;}
    }A[150005],B[350005];
    int n,m;
    long double calc()
    {
    //注意前缀后缀两次的意义是不一样的!
    	long double ret=1e18,sum=0;
    	ll now=1,res=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,res-=B[i].cnt;
    //我们可以枚举前缀的位置,后缀端点是单调的,这里强制了前缀末端只剩一,其它在后缀
    	for(int i=1;i<=n;++i)
    	{
    		res-=B[i].cnt;
    		while(now<=n&&res<=0)
    			sum-=(B[now].cnt-1)*B[now].val*(1-B[now].val)+(1-B[now].val)*B[now+1].val,res+=B[now++].cnt;
    		if(res<=0)break;
    		sum+=(B[i].cnt-1)*B[i].val*(1-B[i].val)+
    			(1-B[i-1].val)*B[i].val;
    		ret=std::min(ret,sum+
    					 (res-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);
    	}
    	res=m,sum=0;
    //求只有前缀的方案
    	for(int i=1;i<=n;++i)
    	{
    		int mn=std::min(res,(ll)B[i].cnt);
    		if(!mn)break;
    		else res-=mn,sum+=(mn-1)*B[i].val*(1-B[i].val)+(1-B[i-1].val)*B[i].val;
    	}
    	return std::min(ret,sum);
    }
    int main()
    {
    	int t=in();
    	while(t--)
    	{
    		n=in(),m=in();int tot=0;
    		for(int i=1;i<=n;++i)
    		{
    			A[i].read();
    			if(!A[i].cnt)--i,--n;
    		}
    		std::sort(A+1,A+n+1);
    		for(int i=1;i<=n;++i)
    		{
    			B[++tot]=node(A[i].val,1);
    			if(--A[i].cnt)
    			{
    				if(A[i].cnt>1)
    					B[++tot]=node(A[i].val,A[i].cnt-1);
    				B[++tot]=node(A[i].val,1);
    			}
    		}
    		B[0].val=1,B[(n=tot)+1].val=0;
    		long double ans=calc();
    //B[i].val=1-B[i].val是说你把前缀后缀倒过来做
    //本来应该是 (1-a0)a1+(1-a1)a2...(1-an-1)an
    //然后变成了 an(1-an-1)...a2(1-a1)+a1(1-a0)
    //所以要变成 1-B[i].val
    		for(int i=1;i<=n;++i)B[i].val=1-B[i].val;
    		std::reverse(B+1,B+n+1);
    		ans=std::min(ans,calc());
    		printf("%.6lf
    ",(double)fabs(ans));
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    [ Linux ] rsync 对异地服务器进行简单同步
    [ Skill ] 遍历整个项目设计的两个思路
    [ Skill ] 不常用的函数笔记
    [ Perl ] Getopt 使用模板
    [ Skill ] 两个 listBox 数据交换的模板
    [ Linux ] "真"后台 nohup
    [ VM ] VirtualBox 压缩 .vdi
    [ Skill ] Layout 工艺移植,还原库调用关系
    win8 hyper-v 禁用不必卸载虚拟机
    BM算法解析(计算机算法-设计与分析导论(第三版))
  • 原文地址:https://www.cnblogs.com/cx233666/p/9853257.html
Copyright © 2020-2023  润新知