bzoj1492/luogu4027 货币兑换 (斜率优化+cdq分治)
设f[i]是第i天能获得的最大钱数,那么
f[i]=max{在第j天用f[j]的钱买,然后在第i天卖得到的钱,f[i-1]}
然后解一解方程什么的,设x[j]=F[j]A[j]∗Rate[j]+B[j],y[j]=Rate[j]∗x[j]的话,就能得到f[i]=max{y[j]∗A[i]+x[j]∗B[i],f[i−1]}
然后再推一波斜率优化的式子,就可以得到,当j1比j2优时,y[j1]−y[j2]x[j1]−x[j2]<−B[i]A[i]
然而−B[i]A[i]这玩意并不单调,所以需要用splay或者cdq分治维护一个斜率递减的凸包,来查询满足上式的斜率最大的那个点。
然而懒得写splay了,所以用cdq分治来做(wa了几发以后才发现还不如去写splay呢写splay就不只是wa了)
我们来分治对所有点的询问。当然需要按照i从小到大来做。
然后在做一个区间的时候,我是想用它的左子区间(保证这些的值已经求完了)去更新右子区间的值。
也就是说,需要先做左子区间,然后做当前区间,最后再做右子区间(原理和寻找宝藏是一样的)
做的时候,左边按x值排序,右边按−B[i]A[i]排序,然后给左半边用栈维护一个凸包,再用右半边的去扫,更新结果就行了。
(别忘了f[i]可以等于f[i-1],具体做法是在l=r的时候更新一下)
(常数好像写得很大..不管了.....)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5 #include<vector> 6 #include<queue> 7 #include<set> 8 #include<ctime> 9 #define LL long long 10 using namespace std; 11 const int maxn=100010; 12 13 LL rd(){ 14 LL x=0;char c=getchar();int neg=1; 15 while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();} 16 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 17 return x*neg; 18 } 19 20 int N,stk[maxn],arr[maxn],tmp[maxn]; 21 double f[maxn],A[maxn],B[maxn],R[maxn]; 22 23 inline double gety(int i){return R[i]*f[i]/(A[i]*R[i]+B[i]);} 24 inline double getx(int i){return f[i]/(A[i]*R[i]+B[i]);} 25 inline double gett(int i){return -B[i]/A[i];} 26 inline double getk(int i,int j){ 27 double dx=getx(i)-getx(j);if(fabs(dx)<=1e-9) dx=1e-9; 28 return (gety(i)-gety(j))/dx; 29 } 30 inline bool cmpl(int a,int b){return getx(a)<getx(b);} 31 inline bool cmpr(int a,int b){return gett(a)<gett(b);} 32 33 void cdq(int l,int r){ 34 if(l>=r){f[arr[l]]=max(f[arr[l]],f[arr[l]-1]);return;} 35 int m=l+r>>1,t=0; 36 cdq(l,m);sort(arr+l,arr+m+1,cmpl); 37 memcpy(tmp+m+1,arr+m+1,4*(r-m));sort(arr+m+1,arr+r+1,cmpr); 38 for(int p=l;p<=m;p++){ 39 while(t>=2&&getk(stk[t],stk[t-1])<getk(stk[t],arr[p])) t--; 40 stk[++t]=arr[p]; 41 }for(int q=m+1;q<=r;q++){ 42 while(t>=2&&getk(stk[t],stk[t-1])<gett(arr[q])) t--; 43 int j=stk[t],i=arr[q]; 44 f[i]=max(f[i],gety(j)*A[i]+getx(j)*B[i]); 45 } 46 memcpy(arr+m+1,tmp+m+1,4*(r-m));cdq(m+1,r); 47 } 48 49 int main(){ 50 //freopen("testdata.in","r",stdin); 51 //freopen(".out","w",stdout); 52 int i,j,k; 53 N=rd(),f[1]=rd(); 54 for(i=1;i<=N;i++){ 55 scanf("%lf%lf%lf",&A[i],&B[i],&R[i]); 56 arr[i]=i; 57 }cdq(1,N); 58 double ans=0; 59 for(i=1;i<=N;i++){ 60 ans=max(ans,f[i]); 61 }printf("%.3lf\n",ans); 62 return 0; 63 }
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· C# 13 中的新增功能实操
· 万字长文详解Text-to-SQL
· Ollama本地部署大模型总结
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(4)
· 卧槽!C 语言宏定义原来可以玩出这些花样?高手必看!