洛谷 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章