把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P4027 [NOI2007] 货币兑换

题面传送门
一道毒瘤题我调两天......
显然有\(dp\)\(dp_i=\max\limits_{j=1}^{i-1}{X_j*a_i+Y_j*b_i}\)其中\(X_i=\frac{dp_ir_i}{r_ia_i+b_i},Y_i=\frac{x_i}{r_i}\)
\(k<j\)\(k\)劣于\(j\)那么就有式子\(-\frac{a_i}{b_i}<\frac{Y_k-Y_j}{X_k-X_j}\)
那么就可以斜率优化了。
但是这道题斜率不递增。
那么就是\(cdq\)分治走起。
总体保证顺序不变。左半边构造单调栈保证\(X_i\)递增,右半边保证\(Y_i\)递增即可。
代码实现:

#include<cstdio>
#include<algorithm>
#include<cmath>
#define eps 1e-6
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,m,k,q[100039],head,tail;
double ans,dp[100039];
struct yyy{double a,b,r;int id;double x,y,k;}s[100039],b[100039];
inline bool cmp1(yyy x,yyy y){return x.k<y.k;}
inline bool cmp3(yyy x,yyy y){return fabs(x.x-y.x)<=eps?x.y>y.y:x.x<y.x;}
inline double slope(int x,int y){return (b[y].y-b[x].y)/(b[y].x-b[x].x);}
inline void slove(int x,int y){
	if(x==y) {dp[x]=max(m,dp[x]);return;}
	int m=x+y>>1,i,j;
	slove(x,m);
	for(i=x;i<=y;i++) b[i]=s[i];
	for(i=x;i<=m;i++) b[i].y=dp[b[i].id]/(b[i].a*b[i].r+b[i].b),b[i].x=b[i].y*b[i].r;
	sort(b+x,b+m+1,cmp3);sort(b+m+1,b+y+1,cmp1);head=0;
	for(i=x;i<=m;i++){
		if(i!=x&&b[i].x-b[i-1].x<eps) continue;
		while(head>=2&&slope(q[head-1],q[head])<slope(q[head],i)) head--;q[++head]=i;
	}
	for(i=m+1;i<=y;i++){
		while(head>=2&&slope(q[head-1],q[head])<=b[i].k)head--;
		
		j=q[head];dp[b[i].id]=max(b[j].x*b[i].a+b[j].y*b[i].b,dp[b[i].id]);
	}
	for(i=m+1;i<=y;i++) dp[i]=max(dp[i-1],dp[i]);
	slove(m+1,y);
}
int main(){
	freopen("1.in","r",stdin);
	register int i;
	scanf("%d%d",&n,&m);
	dp[1]=m;
	for(i=1;i<=n;i++) scanf("%lf%lf%lf",&s[i].a,&s[i].b,&s[i].r),s[i].id=i,s[i].k=-s[i].a/s[i].b;
	slove(1,n);
	printf("%.5lf\n",dp[n]);
}
posted @ 2021-01-12 20:29  275307894a  阅读(41)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end