[概率论 DP] BZOJ 3652 大新闻

边看题解边凑公式

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;

ll n,len;
double p;
double a[105];

inline double part2()
{
	n++;
	double ans=0;
	for (int i=len-1;i>=0;i--)
	{
		double pi=( (double)(n/(1LL<<(i+1)))*(1LL<<i) + (double)max((n%(1LL<<(i+1)))-(1LL<<i),0LL) )/n;
		ans+=pi*(1-pi)*2*(1LL<<i);
	}
	return ans;
}

inline double part1()
{
	n--;
	double ans=0; ll m=n;
	a[0]=n&1?2.0/(n+1):1.0/(n+1);
	for (int i=1;i<len-1;i++)
		if (n&(1LL<<i))
			a[i]=a[i-1]+(double)(1LL<<i)/(n+1)*(1LL<<i)*2+(double)((1LL<<i)-1)/(n+1)*(1LL<<i);
		else
			a[i]=a[i-1]*2+(double)(1LL<<i)/(n+1)*(1LL<<i);
	for (int i=len-1;i>=0;i--)
	{
		if (n&(1LL<<i)) 
		{	
			if (m&(1LL<<i))
			{
				ans+=(double)((1LL<<(i+1))-1)*(m+1-(1LL<<i))/(n+1);
				m=(1LL<<i)-1;
			}
			ans+=(double)(1LL<<i)*(m+1)/(n+1);
		}
		else if (m&(1LL<<i))
		{
			ans+=(double)(1LL<<i)*(m+1-(1LL<<i))/(n+1);
			m^=(1LL<<i);
			ans+=i-1>=0?a[i-1]:0;
		}
	}
	return ans;
}

int main()
{
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	scanf("%lld%lf",&n,&p);
	while ((1LL<<len)<=n) 
		len++;
	double ans1=part1();
	double ans2=part2();
	printf("%.6lf\n",ans1*p+ans2*(1-p));
	return 0;
}


你可能感兴趣的:([概率论 DP] BZOJ 3652 大新闻)