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;
}
原文地址:https://www.cnblogs.com/jz-597/p/14532245.html