zoukankan      html  css  js  c++  java
  • 7006. 2021.03.11【2021省赛模拟】玩游戏

    (n)个人站在一排,每个人抽到一张卡。这些卡是个(1)(n)的排列。

    一开始每个人都不知道自己和别人的卡。

    从前往后,每个人可以选择:

    1. 翻开自己的卡,并且公布这张卡的数字。
    2. 和前面在场的人的手上的牌交换并离场,那个人翻开那张卡并公布那张卡的数字。

    每个人都绝顶聪明,都希望自己最后得到的牌期望最大。

    卡的分配是随机的。问期望下最终留下的人数。

    (kle 50)

    (nle 10^5)

    输出实数。


    (P)表示前面留下来的数字的集合,(R)表示后面的数字的集合。

    结论:如果(maxP< minR),则不换;否则换。

    证明:(maxP< minR)时不换显然,以下证(maxP>minR)时换。

    如果换,收益为(maxP)。如果不换,归纳证明:

    关键时刻为下次(P)中排位变化,或出现(maxP'<minR’)

    以下证明:对于当前的(maxP),设它为(v_x),到下次关键时刻的(v_x'),一定有(v_x'<v_x)

    在关键时刻之前,一定都是选择换。如果是(P)的排位变化,那么此时抽到的值一定小于(P)的次大值。于是(maxP')变成了(P)的次大值。此时显然(v_x'<v_x)

    如果是出现(maxP'<minR'),排位没有变,(v_x)一直是(maxP)。则如果(minR)不变,那么(maxP>minR)变化到(maxP'<minR')(maxP)是变小了;如果(minR)变了,考虑从前推过来,某一刻当前(maxP)用来和当前(minR)交换,此时满足(maxP>minR),则(maxP)变小,然后继续往后推。所以也有(v_x'<v_x)

    综上,到了关键时刻,一定有(v_x'<v_x)

    用DYP的话来说,就是:

    以某个时刻的(v_x)标准,它可能会换到(v_x)以上,因为后面还会继续换所以不管它。于是它肯定要换小。

    (minR)不改变的时候,无论怎么换都会保持(maxP>minR),因为换来的东西都比(minR)大。

    换小后如果产生了一些显著变化,它可能不是最大了,也有可能把(minR)换了下来。(即“关键时刻”)

    接下来证明:如果在(maxP>minR)时不换,没可能得到比(maxP)更大的收益。设当前点为(v_y)

    首先下一个关键时刻总是存在的。最后一次一定是关键时刻。

    如果开始时(v_y<maxP),如果(v_y)能得到更大的收益,那么(P)中大于(v_y)的一定的排位一定要换到(v_y)后面(指值变得更小),使(v_y)露出来。从(v_y)露出来那个时候开始记,根据上面的结论,到达下一个关键时刻的时候,(v_y)一定会变小,并且可能换到后面去。重复刚刚的分析,最终(v_y)不会变大。

    如果开始时(v_y>maxP),则到下一次关键时刻的时候,(v_y)可能会换到后面去,可能会换掉(minR)但由于之前(minP>minR)所以一定会换到后面去。然后就和上面一样了。

    证毕。

    模拟可以验证最终保留在(P)中的元素一定都是在原序列中的后缀最小值。

    于是(S_0(n)=sum_{i=1}^nfrac{1}{n}=H(n))(调和级数)

    (S)的生成函数为(F)(F_k(x)=frac{-ln(1-x)}{(1-x)^{k+1}})

    求导得((F_k(x))'=frac{1}{(1-x)^{k+2}}+(k+1)F_{k+1}(x))

    由于(F_k(x)[x^n]=frac{1}{n}(F_{k}(x))'[x^{n-1}]),得到(nS_k(n)=(k+1)S_{k+1}(n-1)+inom{n+k}{k+1})

    于是可以从(S_{k}(n+1))推到(S_{k+1}(n))

    最终算(H(n))的时候,(n)小的时候暴力算,(n)大的时候根据常识有(H(n))约等于(ln(n)+gamma+frac{1}{2n}),其中(gamma)为欧拉常数$$。

    题解中也提到(S_k(n))约等于(frac{n^k}{k!}(H(n)-H(k)))。不知道是什么东西。


    using namespace std;
    #include <bits/stdc++.h>
    #define ll long long
    long double C(ll m,ll n){
    	long double p=1;
    	for (ll i=m;i>m-n;--i) p*=i;
    	for (ll i=1;i<=n;++i) p/=i;
    	return p;
    }
    long double S(ll k,ll n){
    	if (k==0){
    		long double s=0;
    		if (n<=1e7)
    			for (int i=1;i<=n;++i)	
    				s+=1.0/i;
    		else
    			s=log(n)+0.5772156649+1.0/(2*n);
    		return s;
    	}
    	return ((n+1)*S(k-1,n+1)-C(n+k,k))/k;
    }
    int main(){
    //	freopen("in.txt","r",stdin);
    	freopen("game.in","r",stdin);
    	freopen("game.out","w",stdout);
    	cout.unsetf(ios::fixed);
        cout.setf(ios::scientific);
        cout.precision(9);
        ll k,n;
        cin>>k>>n;
    	cout<<S(k,n);
    	return 0;
    }
    
  • 相关阅读:
    rocketmq的broker如何同步信息的?
    SO_LINGER 选项
    哈哈哈
    NAG博客目录
    事后分析$eta$
    项目展示$eta$
    测试报告$eta$
    发布声明$eta$
    Scrum meeting 10
    技术博客6--Django实现列表分页
  • 原文地址:https://www.cnblogs.com/jz-597/p/14532245.html
Copyright © 2011-2022 走看看