三分法
这么简单的算法却一直不会,真是不太应该。。
BZOJ2330 一道三分裸题,但因为姿势不太对调了挺久,然后学会了保留有效位数输出小数,只要开<iomanip>库再cout<<setprecision(m)<<f<<endl就行啦,不过这道题似乎仍然不太资磁
#include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<iomanip> using namespace std; int n,m,i;double ans,eps,a[25],b[25]; double cal2(double nd,double sl){ double res=0; for(int i=1;i<=n;i++){ double s=100/(1+exp(nd-sl*a[i])); if(s<1e-12||s>=100)return 1e200; res+=b[i]*log(100/s)+(100-b[i])*log(100/(100-s)); } return res; } double cal(double nd){ double l=0,r=1,mid1,mid2; while(r-l>eps){ mid1=(l+r)/2;mid2=(mid1+r)/2; if(cal2(nd,mid1)>cal2(nd,mid2))l=mid1;else r=mid2; } return cal2(nd,(l+r)/2); } double print(double ans){ long long a=(long long)ans; int digit=0; for(int tmp=a;tmp;tmp/=10)digit++; if(m<=digit){ int bit[100];for(*bit=0;a;a/=10)bit[++*bit]=a%10; for(int i=*bit;i>=1 &&m;i--,digit--,m--) putchar(bit[i]+'0'); while(digit--)putchar('0'); }else{ cout<<a<<'.';m-=digit; while(m--)ans-=(int)ans,ans*=10,printf("%d",(int)ans); } } int main(){ scanf("%d%d",&n,&m); eps=1.0;for(i=1;i<=m;i++)eps/=10.0; for(i=1;i<=n;i++)scanf("%lf",&a[i]);sort(a+1,a+n+1); for(i=1;i<=n;i++)b[i]=(i-1)*100.0/(n-1); double l=0.0,r=10.0,mid1,mid2; while(r-l>eps){ mid1=(l+r)/2;mid2=(mid1+r)/2; if(cal(mid1)>cal(mid2))l=mid1;else r=mid2; } print(cal((l+r)/2)); }
BZOJ1857 更裸的三分,不过因为R变量用重复了也调了好久。。
#include<cstdio> #include<cmath> #define eps 1e-8 double ax,ay,bx,by,cx,cy,dx,dy,ex,ey,P,Q,R; double dis(double x1,double y1,double x2,double y2){return sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));} double cal(double a,double b){ double l=0,r=1,mid1,mid2,x,y,ret1,ret2; while(r-l>eps){ mid1=(l+r)/2;mid2=(mid1+r)/2; x=dx+(cx-dx)*mid1;y=dy+(cy-dy)*mid1; ret1=dis(a,b,ax,ay)/P+dis(a,b,x,y)/R+dis(x,y,dx,dy)/Q; x=dx+(cx-dx)*mid2;y=dy+(cy-dy)*mid2; ret2=dis(a,b,ax,ay)/P+dis(a,b,x,y)/R+dis(x,y,dx,dy)/Q; if(ret1>ret2)l=mid1;else r=mid2; } mid1=(l+r)/2;x=dx+(cx-dx)*mid1;y=dy+(cy-dy)*mid1; return dis(a,b,ax,ay)/P+dis(a,b,x,y)/R+dis(x,y,dx,dy)/Q; } int main(){ scanf("%lf%lf%lf%lf",&ax,&ay,&bx,&by);ex=dis(ax,ay,bx,by); scanf("%lf%lf%lf%lf",&cx,&cy,&dx,&dy);ey=dis(cx,cy,dx,dy); scanf("%lf%lf%lf",&P,&Q,&R); double l=0,r=1,mid1,mid2,x,y,ret1,ret2; while(r-l>eps){ mid1=(l+r)/2;mid2=(mid1+r)/2; x=ax+(bx-ax)*mid1;y=ay+(by-ay)*mid1; ret1=cal(x,y); x=ax+(bx-ax)*mid2;y=ay+(by-ay)*mid2; ret2=cal(x,y); if(ret1>ret2)l=mid1;else r=mid2; } mid1=(l+r)/2;x=ax+(bx-ax)*mid1;y=ay+(by-ay)*mid1; printf("%.2lf",cal(x,y)); }
BZOJ3874 单调性贪心+三分,因为一个LL没开调了好久。。
#include<cstdio> #include<algorithm> #define N 333 using namespace std; typedef long long LL; LL m,f,n,i,top,midl,midr,l,r,ans,ansl,ansr; struct EG{LL x,y;}eg[N],q[N]; bool cmp(EG a,EG b){return a.x<b.x;} LL calc(LL x){ LL xm,ans=0,days=0,la,i; xm=m-x*f;if(xm<0)return 0; for(i=1;i<=top;i++){ if(days<=q[i].y){ la=min(q[i].y-days+(LL)1,xm/q[i].x/x); ans+=la*x;xm-=q[i].x*x*la; days+=la; } if(days<=q[i].y){ la=min(x,xm/q[i].x); ans+=la;xm-=q[i].x*la;days++; } } return ans; } int main(){ scanf("%lld%lld%lld",&m,&f,&n); for(i=1;i<=n;i++)scanf("%lld%lld",&eg[i].x,&eg[i].y); sort(eg+1,eg+n+1,cmp); q[++top]=eg[1]; for(i=2;i<=n;i++)if(eg[i].y>q[top].y)q[++top]=eg[i]; l=1;r=m/(f+q[1].x); ans=max(calc(l),calc(r)); while(l<=r){ midl=l+(r-l)/(LL)3;midr=r-(r-l)/(LL)3; ansl=calc(midl);ansr=calc(midr); ans=max(ans,max(ansl,ansr)); if(ansl<ansr)l=midl+1;else r=midr-1; } printf("%lld\n",ans); }
BZOJ3203 很明显就是求max{sum[i]/d[i]},由于sum[i]递增且每次相对位置不变,相当于求1~i中到点(sum[i],d*i+y)的最大斜率。可以维护一个单调队列,然后在上面三分得到答案
#include<bits/stdc++.h> int n,i,l,r,p,t,m1,m2;double x,y,v,d,w,ans;struct Q{double x,y;}q[100100],o; Q operator-(Q a,Q b){Q t;t.x=a.x-b.x;t.y=a.y-b.y;return t;} double operator*(Q a,Q b){return a.x*b.y-a.y*b.x;} double xl(Q a,Q b){return (b.y-a.y)/(b.x-a.x);} int main(){ for(scanf("%d%lf",&n,&d),i=1;i<=n;i++){ for(scanf("%lf%lf",&x,&y),o=Q{d*i,v},v+=x;t>1&&(o-q[t])*(q[t]-q[t-1])>=0;)t--; for(w=0,q[++t]=o,o=Q{y+d*i,v},l=1,r=t;r-l>2;){ p=(r-l+1)/3;m1=l+p;m2=r-p; if(xl(q[m1],o)<xl(q[m2],o))l=m1;else r=m2; } for(p=l;p<=r;p++)w=std::max(w,xl(q[p],o));ans+=w; } printf("%.0f",ans); }
BZOJ4311 按时间建立线段树,对询问离线拉链,每个点求出凸壳后每个询问三分找答案即可
#include<bits/stdc++.h> #define N 200200 using namespace std;typedef long long LL; int n,m,i,x,y,t,o,tot,fir[N*3],ne[3333333],la[3333333];LL ans[N]; struct P{int x,y;}a[N],b[N],c[N],p[N],q[N];bool cmp(P a,P b){return a.x<b.x||a.x==b.x&&a.y>b.y;} void ins(int k,int l,int r,int x,int y,int z){ if(x<=l&&r<=y){la[++tot]=z;ne[tot]=fir[k];fir[k]=tot;return;} int mid=l+r>>1;if(x<=mid)ins(k<<1,l,mid,x,y,z); if(y>mid)ins(k<<1|1,mid+1,r,x,y,z); } void ask(int x){ int l,r,w,m1,m2;LL s1,s2; for(l=1,r=t;l<=r;){ w=(r-l)/3,m1=l+w,m2=r-w;s1=1ll*c[x].x*q[m1].x+1ll*c[x].y*q[m1].y;s2=1ll*c[x].x*q[m2].x+1ll*c[x].y*q[m2].y; if(s1>s2)r=m2-1,ans[x]=max(ans[x],s1);else l=m1+1,ans[x]=max(ans[x],s2); } } void fz(int k,int l,int r){ int i,w=0,mid=l+r>>1;if(l<r)fz(k<<1,l,mid),fz(k<<1|1,mid+1,r); for(i=fir[k];i;i=ne[i])p[++w]=a[la[i]];if(!w)return;sort(p+1,p+w+1,cmp); for(q[t=1]=p[1],i=2;i<=w;q[++t]=p[i++])for(;t>1&&1ll*(q[t].y-q[t-1].y)*(p[i].x-q[t].x)<=1ll*(p[i].y-q[t].y)*(q[t].x-q[t-1].x);t--); for(i=l;i<=r;i++)if(c[i].x)ask(i); } int main(){ for(scanf("%d",&n),i=1;i<=n;i++){ scanf("%d%d",&o,&x); if(o==1)scanf("%d",&y),a[++m]=P{x,y},b[m]=P{i,n}; if(o==2)b[x].y=i; if(o==3)scanf("%d",&y),c[i]=P{x,y}; } for(i=1;i<=m;i++)ins(1,1,n,b[i].x,b[i].y,i); for(fz(1,1,n),i=1;i<=n;i++)if(c[i].x)printf("%lld\n",ans[i]); }
2015年9月14日 12:15
其实应该是
cout<<fixed<<setprecision(m)<<f<<endl;
2016年5月16日 00:57
第一题是bzoj 3330吧……