BZOJ 1492 货币兑换 Cash CDQ分治
这题n2算法就是一个维护上凸包的过程.
也可以用CDQ分治做.
我的CDQ分治做法和网上的不太一样,用左边的点建立一个凸包,右边的点在上面二分.
好处是思路清晰,避免了凸包的插入删除,坏处是多了一个log.
这题数据很水,同时注意精度.
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<ctime> #include<string> #include<iomanip> #include<algorithm> #include<map> using namespace std; #define LL long long #define FILE "cash" #define up(i,j,n) for(int i=j;i<=n;++i) #define db double #define ull unsigned long long #define eps 1e-12 #define pii pair<int,int> int read(){ int x=0,f=1,ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f*x; } const int maxn=200010,maxm=20000,limit=1e6,mod=(int)(7+1e9+0.1); const db inf=(1e18); template<class T>bool cmax(T& a,T b){return a<b?a=b,true:false;} template<class T>bool cmin(T& a,T b){return a>b?a=b,true:false;} template<class T>T min(T& a,T& b){return a<b?a:b;} template<class T>T max(T& a,T& b){return a>b?a:b;} int n,N,M; db f[maxn],X[maxn],Y[maxn],A[maxn],B[maxn],sp[maxn]; struct vec{ db x,y; vec(db x=0,db y=0):x(x),y(y){} vec operator+(const vec& a){return vec(x+a.x,y+a.y);} vec operator-(const vec& a){return vec(x-a.x,y-a.y);} vec operator*(db b){return vec(x*b,y*b);} }q[maxn],w[maxn]; int dcmp(db x){if(fabs(x)<eps)return 0;return x>0?1:-1;} bool operator<(vec a,vec b){return a.x<b.x||(!dcmp(a.x-b.x)&&a.y<b.y);} db dot(vec a,vec b){return a.x*b.x+a.y*b.y;} db cro(vec a,vec b){return a.x*b.y-a.y*b.x;} db len(vec a){return sqrt(dot(a,a));} void build(int l,int r){ N=0; up(i,l,r)q[++N]=vec(f[i]*X[i],f[i]*Y[i]); sort(q+1,q+N+1); M=0; w[++M]=q[1]; up(i,2,N){ while(M>1&&dcmp(cro(w[M]-w[M-1],q[i]-w[M]))>=0)M--; w[++M]=q[i]; } } db getK(vec a,vec b){ if(!dcmp(b.x-a.x))return inf; if(!dcmp(b.y-a.y))return -inf; return (b.y-a.y)/(b.x-a.x); } vec query(db sp){ int left=2,right=M-1; if(getK(w[M],w[M-1])>sp)return w[M]; if(getK(w[1],w[2])<sp)return w[1]; while(left+1<right){ int mid=(left+right)>>1; if(getK(w[mid],w[mid+1])<sp&&getK(w[mid-1],w[mid])>sp)return w[mid]; if(getK(w[mid],w[mid-1])<sp&&getK(w[mid],w[mid+1])<sp)right=mid; else left=mid; } int mid=left; if(getK(w[mid],w[mid+1])<sp&&getK(w[mid-1],w[mid])>sp)return w[mid]; mid=right; if(getK(w[mid],w[mid+1])<sp&&getK(w[mid-1],w[mid])>sp)return w[mid]; return w[left]; } void cdq(int l,int r){ if(l==r){ cmax(f[l],f[l-1]); //printf("%d %.3lf\n",l,f[l]); return; } int mid=(l+r)>>1; cdq(l,mid); build(l,mid); up(i,mid+1,r){ vec k=query(sp[i]); cmax(f[i],f[i-1]); cmax(f[i],k.x*A[i]+k.y*B[i]); } cdq(mid+1,r); } int main(){ freopen(FILE".in","r",stdin); freopen(FILE".out","w",stdout); scanf("%d%lf",&n,&f[0]); up(i,1,n){ db x,y,k; scanf("%lf%lf%lf",&x,&y,&k); A[i]=x,B[i]=y; X[i]=k/(x*k+y); Y[i]=1.0/(x*k+y); sp[i]=-A[i]/B[i]; } cdq(1,n); printf("%.3lf\n",f[n]); return 0; }