JZOJ 5481. 【清华冬令营2018模拟】第二题

来源:互联网 发布:微信定位软件 编辑:程序博客网 时间:2024/05/16 11:22

题目大意

给定一个长度为L的环,此环上有n个点,d[i]表示i-1和i的距离。
每个点有一权值w[i],但是w[n]为在[a,b]之间等概率分布的一个数。
假设选择x为特殊点,那么对答案的贡献为sum[x].
设x到i的两条路径长度分别为l1,l2.

sum[x]=Σni=1w[i]l1l2

选择sum[x]最小的点x作为特殊点。
那么,每个点被选为特殊点的概率为多少?
数据范围
对于20%的数据,n≤1000。
对于另20%的数据,a=b。
对于另20%的数据,w[1]=w[2]=……=w[n-1]<a≤b,d[i]=1。
对于100%的数据n≤100000,a≤b≤10000,w[i]≤10000,d[i]≤10。

题解

由于w[n]是未知的,设它为x,那么sum[i]可以用k[i]*x+b[i]来表示。
qzd[i]=Σij=1d[j]
将式子展开,即

sum[i]=Σi1j=1w[j](qzd[i]qzd[j])(L(qzd[i]qzd[j]))+Σn1j=i+1w[j](qzd[j]qzd[i])(L(qzd[j]qzd[i]))+w[n](qzd[n]qzd[i])(L(qzd[n]qzd[i]))

显然,$k[i]=(qzd[n]-qzd[i])*(L-(qzd[n]-qzd[i]))

b[i]=Σi1j=1w[j](qzd[i]qzd[j])(L(qzd[i]qzd[j]))
       +Σn1j=i+1w[j](qzd[j]qzd[i])(L(qzd[j]qzd[i]))
n1000,那么O(n2)直接算k[i],b[i]就好了。
问题是怎么将时间复杂度均摊成O(1)
显然计算k可均摊O(1),直接将式子摆出来就OK了
均摊O(1),就是说在O(1)时间内通过求出b[i]b[i1]
然后得到n条直线。
接着维护个上凸壳就好了。
由于维护凸壳方面做得不够好,所以要加强练习。
首先我们要找当x值一定时,所有直线的y的min,那么按照斜率k从大到小排序,然后按照交点的横坐标建立单调栈。画画图,考虑淘汰哪条直线。

!!!要注意的地方


①这个式子我一早就推出来了,但是浪费了很多的改题时间。为什么?因为自己的一些毛病,自以为是将符号弄反,可能将某些变量搞错。
因此,在做题的时候,确定这个式子是对的,那就将它留着,然后一个一个将里面的变量拆到Σ外面去。
注意读入的每一个变量类型,不要被样例坑!!!!!
③这是一次维护凸壳的好机会,不要忘记用单调栈维护了!!!!!

代码

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define N 100010#define DB double#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;struct note{    DB k,b;    int id;};note li[N];struct note1{    DB data,cnt;    int wz;};note1 st[N];DB a,b;int i,j,l,r,n,m,cnt;DB qz[N],qzd[N],d[N],w[N],c[N],k[N];int ans[N],top;DB temp,tl,tr,mx,L,sum,D,s2,last;DB yy[N],Ans[N];DB dis(int x,int y){return qzd[y]-qzd[x];}DB jd(note x,note y){return 1.0*(y.b-x.b)/(x.k-y.k);}bool cmp(note x,note y){return x.k>y.k||(x.k==y.k&&x.b<y.b)||(x.k==y.k&&x.b==y.b&&x.id<y.id);}void put_in(int x,int y){    if(li[x].k==li[st[top].wz].k)return;    while(top>1 && st[top].data-jd(li[st[top].wz],li[x])>1e-7)top--;    st[++top].wz=x;    st[top].cnt=y;    if(top>1)st[top].data=jd(li[st[top-1].wz],li[st[top].wz]);}int main(){    scanf("%d%lf%lf\n",&n,&a,&b);    fo(i,1,n-1)scanf("%lf",&w[i]),sum+=w[i];    fo(i,1,n)scanf("%lf",&d[i]),L+=d[i];    fo(i,2,n-1)tr+=dis(1,i)*w[i];    fo(i,1,n){        qzd[i]=qzd[i-1]+d[i];        qz[i]=qz[i-1]+w[i];    }    fo(i,1,n-1)s2+=qzd[i]*w[i];    fo(i,1,n-1){        k[i]=dis(i,n)*(L-dis(i,n));        if(i==1){            fo(j,2,n-1)c[1]+=dis(1,j)*(L-dis(1,j))*w[j];        } else{            D=qzd[i]-qzd[i-1];            temp=D*(L-D)*(w[i-1]-w[i]);            temp+=D*D*(sum-w[i]-w[i-1]);            temp+=D*L*(qz[i-2]-qz[n-1]+qz[i]);            tl=w[i-1]*D-qzd[i]*qz[n-1]+s2;            temp+=2*D*tl;            c[i]=c[i-1]+temp;        }    }    fo(i,1,n-1)c[n]+=dis(i,n)*(L-dis(i,n))*w[i];    if(a==b){        fo(i,1,n){            yy[i]=k[i]*a+c[i];            if(i==1)mx=yy[i];            if(yy[i]<mx){                ans[ans[0]=1]=i;                mx=yy[i];            } else            if(yy[i]-mx<1e-7)ans[++ans[0]]=i;        }        fo(i,1,n)            if(yy[i]-mx>1e-7)Ans[i]=0;else Ans[i]=1.0/ans[0];        fo(i,1,n)printf("%.3lf\n",Ans[i]);         return 0;    }    fo(i,1,n)li[i].k=k[i],li[i].b=c[i],li[i].id=i;    sort(li+1,li+n+1,cmp);    for(l=1,r=0;l<=n;l=r+1){        while(li[l].k==li[r+1].k&&li[l].b==li[r+1].b)r++;        put_in(l,r-l+1);    }    st[top+1].data=2147483647.0;    last=a;    fo(i,2,top+1)        if(st[i].data-a>=1e-7){            if(st[i].data-b>1e-7){                Ans[li[st[i-1].wz].id]=(b-last)/(b-a)/st[i-1].cnt;                fo(j,st[i-1].wz+1,n){                    if(li[j].k!=li[j-1].k||li[j].b!=li[j-1].b)break;                    Ans[li[j].id]=Ans[li[st[i-1].wz].id];                }                break;            }            Ans[li[st[i-1].wz].id]=(st[i].data-last)/(b-a)/st[i-1].cnt;            fo(j,st[i-1].wz+1,n){                if(li[j].k!=li[j-1].k||li[j].b!=li[j-1].b)break;                Ans[li[j].id]=Ans[li[st[i-1].wz].id];            }            last=st[i].data;        }    fo(i,1,n)printf("%.3lf\n",Ans[i]);    return 0;}