usaco铂金组的题
qwq
感觉有些题解其实说的并不是很明白啊。
首先,这个题目其实并不好入手的啊。
首先,这里先给定一个性质,就是说,在一个长度为 L L L的数轴上,当前在 x x x的位置,按照题目给的方式去走的话,走到 L L L这一端的概率是 x L \frac{x}{L} Lx,另一端的概率是 L − x L \frac{L-x}{L} LL−x
证明:
不难发现,假设我们设
f
(
x
)
f(x)
f(x)表示
x
x
x这个点到
L
L
L的概率,那么
f
(
L
)
=
1
,
f
(
0
)
=
0
f(L) = 1,f(0)=0
f(L)=1,f(0)=0
由于 f ( x ) = f ( x − 1 ) + f ( x + 1 ) 2 f(x)=\frac{f(x-1)+f(x+1)}{2} f(x)=2f(x−1)+f(x+1)的形式
所以,不难发现 f ( x ) f(x) f(x)是一个等差数列的形式
那么就能推出来上面这个性质了。
那么对于一个点来说,要么原地不动,直接停止,要么就是向两边走。
假设我们靠左走,到
a
a
a处停止,右边则是到
b
b
b处停止
那么我们的期望收益就是 e = m a x ( ( i − a ) v a l b b − a + ( b − i ) v a l a b − a , v a l i ) e =max( \frac{(i-a)val_b}{b-a} + \frac{(b-i)val_a}{b-a} , val_i ) e=max(b−a(i−a)valb+b−a(b−i)vala,vali)
qwq经过一些脑洞,我们惊奇的发现。
如果将对于每一个点看成一个二维平面的点 ( x , v a l x ) (x,val_x) (x,valx),那么上述柿子,就是 i i i在 a , b a,b a,b形成的直线上的对应的函数值。
因为上式等于 v a l b − v a l a b − a + v a l a ( b − a ) b − a \frac{val_b-val_a}{b-a} + \frac{val_a(b-a)}{b-a} b−avalb−vala+b−avala(b−a)
稍微合并一下就能得到上面这个柿子了。
那么我们发现,对于一个非停止点,他的权值是小于对应的函数值的,但是停止点,则是大于两边的函数值,这时候,我们发现
这就是一个凸包啊!
我们只需要统计出每个点两边最近的一个凸包上的点,然后更新一下就 o k ok ok了,貌似确实是这样的,那么这个题就这么做完了
但是有一个需要注意的地方就是说,我们需要把 ( 0 , 0 ) 和 ( n + 1 , 0 ) (0,0)和(n+1,0) (0,0)和(n+1,0)也加入凸包,因为两端是给出的停止点。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk make_pair
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 3e5+1e2;
const int ptx = 1e5;
struct Point
{
int x,y;
};
int val[maxn],l[maxn],r[maxn];
int n,m;
Point st[maxn];
int top;
Point a[maxn];
int tag[maxn];
Point b[maxn];
int tmp;
int ans[maxn];
Point operator + (Point a,Point b)
{
return (Point){a.x+b.x,a.y+b.y};
}
Point operator - (Point a,Point b)
{
return (Point){a.x-b.x,a.y-b.y};
}
int chacheng(Point a,Point b)
{
return a.x*b.y-a.y*b.x;
}
int dis(Point a,Point b)
{
Point now = a-b;
return now.x*now.x+now.y*now.y;
}
Point ymh;
bool cmp(Point a,Point b)
{
int now = chacheng(a-ymh,b-ymh);
if (now>0) return 1;
if (now<0) return 0;
else
{
int d1 = dis(a,ymh);
int d2 = dis(b,ymh);
return d1<d2;
}
}
void solve(int n)
{
int mn = 1e9,pos=0;
for (int i=1;i<=n;i++)
{
if (a[i].y<mn)
mn=a[i].y,pos=i;
else
{
if (a[i].y==mn && a[i].x<a[pos].x)
mn=a[i].y,pos=i;
}
}
swap(a[1],a[pos]);
ymh = a[1];
sort(a+1,a+1+n,cmp);
top=1;
st[1]=a[1];
a[n+1]=a[1];
for (int i=2;i<=n+1;i++)
{
while(top>1 && chacheng(st[top]-st[top-1],a[i]-st[top-1])<=0) top--;
st[++top]=a[i];
}
for (int i=1;i<top;i++) b[++tmp] = st[i],tag[st[i].x]=1;
}
signed main()
{
n=read();
for (int i=1;i<=n;i++) val[i]=read(),a[i].x=i,a[i].y=val[i];
int nn = n;
++nn;
a[nn].x=0,a[nn].y=0;
++nn;
a[nn].x=n+1,a[nn].y=0;
solve(nn);
l[0]=0;
for (int i=1;i<=n;i++)
{
if(tag[i]) l[i]=i;
else l[i]=l[i-1];
}
r[n+1]=n+1;
for (int i=n;i>=1;i--)
{
if (tag[i]) r[i]=i;
else r[i]=r[i+1];
}
for (int i=1;i<=n;i++)
{
//cout<<r[i]<<" "<<l[i]<<endl;
if(l[i]==r[i]) ans[i]=val[i]*ptx; //这个点是凸包上的点
else
{
//这一步是求这个点在两侧凸包上的点的 连线上的函数值。
ans[i]=((val[r[i]]-val[l[i]])*(i-l[i])+val[l[i]]*(r[i]-l[i]))*ptx/(r[i]-l[i]);
}
}
for (int i=1;i<=n;i++)
{
cout<<ans[i]<<"\n";
}
return 0;
}