洛谷 5242 [USACO19FEB]Cow Dating P 题解

博客观赏效果更佳

题意简述

Bessie要找 nn 头奶牛约会,第 ii 头奶牛同意的概率是 pi106\dfrac{p_i}{10^6}。Bessie 会对一个连续区间的所有奶牛邀请约会,但是她只希望恰好一个同意来约会。请求出所有区间中,恰好只有一个奶牛同意约会的概率的最大值。输出这个最大的概率乘以 10610^6 后下取整的结果。

n<=106n<=10^60<=pi<=1060<=p_i<=10^6

思路框架

ai=1pia_i=1-p_ibi=pi1pib_i=\dfrac{p_i}{1-p_i}

一段区间 [l,r][l,r] 中只有恰好一个奶牛同意邀请的概率为: 设 A=i=lr(1pi)=i=lraiA=\prod\limits_{i=l}^{r} (1-p_i)=\prod\limits_{i=l}^{r} a_i,那么这个概率为 i=lrpi×A1pi=A×i=1npi1pi=A×B\sum\limits_{i=l}^{r}p_i\times \dfrac{A}{1-p_i}=A\times \sum\limits_{i=1}^{n} \dfrac{p_i}{1-p_i}=A\times B
(设 B=i=1npi1piB=\sum\limits_{i=1}^{n} \dfrac{p_i}{1-p_i}

证明一下单调性,就珂以 O(n)O(n) 做了。

具体思路

我们考虑从 [l,r][l,r] 变成 [l,r+1][l,r+1] 会怎么样。

[l,r][l,r] 的答案是 A×BA\times B

[l,r][l,r] 变成 [l,r+1][l,r+1] 的时候,AA 新乘了一个 ar+1a_{r+1}BB 新加了一个 br+1b_{r+1}。答案变成:

A×ar+1×(B+br+1)=A×(ar+1B+ar+1br+1)=A×(ar+1B+pr+1)A\times a_{r+1}\times (B+b_{r+1})=A\times (a_{r+1}B+a_{r+1}b_{r+1})=A\times (a_{r+1}B+p_{r+1})

假设这个答案比 [l,r][l,r] 的答案优,那么 ar+1B+pr+1>Ba_{r+1}B+p_{r+1}>B

简单移项发现: B<1B<1

那么对于每个 ll ,我们找到一个最大的 rr 满足 Bl,r=i=lrbi<1B_{l,r}=\sum\limits_{i=l}^{r} b_i<1,那么 [l,r+1][l,r+1] 就是以 ll 为左端点的最优解了。而随着 ll 的增大,BB 值显然会减小,那么 rr 就会不断往右移(或者不变)。这就是单调性,利用这单调性,珂以轻松的 O(n)O(n) 求解。

代码

#include <bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
	#define N 1666666
	#define real double
	#define F(i,l,r) for(int i=l;i<=r;++i)
	#define D(i,r,l) for(int i=r;i>=l;--i)
	#define Fs(i,l,r,c) for(int i=l;i<=r;c)
	#define Ds(i,r,l,c) for(int i=r;i>=l;c)
	#define MEM(x,a) memset(x,a,sizeof(x))
	#define FK(x) MEM(x,0)
	#define Tra(i,u) for(int i=G.Start(u),__v=G.To(i);~i;i=G.Next(i),__v=G.To(i))
	#define p_b push_back
	#define sz(a) ((int)a.size())
	#define iter(a,p) (a.begin()+p)
	void R1(int &x)
	{
	    x=0;char c=getchar();int f=1;
	    while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
	    while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	    x=(f==1)?x:-x;
	}
	void Rd(int cnt,...)
	{
	    va_list args;
	    va_start(args,cnt);
	    F(i,1,cnt) 
	    {
	        int* x=va_arg(args,int*);R1(*x);
	    }
	    va_end(args);
	}

	int n;
	real p[N];
	void Input()
	{
		R1(n);
		F(i,1,n) {scanf("%lf",&p[i]); p[i]/=1e6;}
	}

	real a[N],b[N];
	void Soviet()
	{
		F(i,1,n) a[i]=1.0-p[i],b[i]=p[i]/(1.0-p[i]);
       //计算出a,b
		int p=0;
       //p维护满足条件的最大的r值
		real A=1.0,B=0.0;
       //一定注意!A的初始值为1!
		real ans=0.0;
		F(i,1,n)
		{
			while(p<n and B<1.0) ++p,A*=a[p],B+=b[p];
           //此时p是最大的满足B<1的值+1
			ans=max(ans,A*B);
          //那么A*B就是以i为左端点的最优解了
			
			A/=a[i]; B-=b[i];
		}
		printf("%d\n",(int)(ans*1e6));
	}

	#define Flan void
	Flan IsMyWife()
	{
		Input();
		Soviet();
	}
}
int main()
{
	Flandre_Scarlet::IsMyWife();
	getchar();getchar();
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章