題解 [USACO18DEC]Balance Beam
阿新 • • 發佈:2019-01-13
被概率衝昏的頭腦~~~
我們先將樣例在圖上畫下來:
會發現,最大收益是:
看出什麼了嗎?
這不就是凸包嗎?
跑一遍凸包就好了呀,這些點中,如果i號點是凸包上的點,那麼它的ans就是自己(第二個點),不然的話,從上圖來看,i的ans肯定和他相鄰的兩個是凸包邊界的點有關(0節點和2節點),那麼怎麼求這個ans呢?(第x號點為橫座標為x的點)
實際上我也不知道就是個期望公式啊!
l[i]記錄i號點往左走第一個為凸包邊界的點(如果i為1號,那麼l[i]為0,特殊的,如果i為2號,那麼l[i]就是本身),r[i]同理。當l[x]==r[x]時,x時邊界。
就是這個方程: (f[l[i]])*(r[i]-i)+f[r[i]]*(i-l[i])))/(r[i]-l[i]);
基礎的期望方程,在此不再贅述(實際上是不會證)
關於凸包,在這貼一波yyb大神的部落格:傳送門戳我QwQ(順便膜一波yyb大神%%%)
#include<bits/stdc++.h> #define ll long long #define inf 0x3f3f3f3f #define RI register int #define F 100000 using namespace std; const int NS=1e5+5; ll f[NS],l[NS],r[NS],hep[NS]; //f如題,l[i]/r[i]如上文,hep為凸包 template <typename _Tp> inline void IN(_Tp&x){ char ch;bool flag=0;x=0; while(ch=getchar(),!isdigit(ch))if(ch=='-')flag=1; while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); if(flag)x=-x; } int main(){ int n,top=0;IN(n);hep[++top]=0;//注意先加入0! for(int i=1;i<=n;++i)IN(f[i]); for(int i=1;i<=n+1;++i){//凸包 while(top>=2){ int a=hep[top],b=hep[top-1]; if(((f[a]-f[b])*(i-a))<((f[i]-f[a])*(a-b)))--top; else break; }hep[++top]=i; } for(int i=1;i<top;++i){ //中間的節點的l,r值都為hep[i]/hep[i+1] for(int j=hep[i]+1;j<hep[i+1];++j){ l[j]=hep[i],r[j]=hep[i+1]; }l[hep[i]]=hep[i],r[hep[i]]=hep[i]; } for(int i=1;i<=n;++i){ ll ans=0;//記得LL! if(l[i]==r[i])ans=f[i]*F;//為邊界,直接跳下最優 else ans=(F*(f[l[i]]*(r[i]-i)+f[r[i]]*(i-l[i])))/(r[i]-l[i]);//否則用方程算 printf("%lld\n",ans); }return 0; }