1. 程式人生 > >bzoj1492 NOI2007 貨幣兌換Cash

bzoj1492 NOI2007 貨幣兌換Cash

題目描述

題解:

題目都提示了,

很明顯要導一波式子:

$$dp[i]=max( dp[i-1] , \frac{ dp[j] } { A[j]*R[j]+B[j] } * (A[i]*R[j]+B[i]))$$

後面那個東西相當與將第j天的R[j]個A和1個B綁在一起。

$dp[i-1]$沒什麼好說的,關鍵是後面那個。

看起來還可以提一下。

$$dp[i]=\frac{dp[j]}{A[j]*R[j]+B[j]}*(A[i]*R[j]+B[i])$$

把右面$A[i]$移項:

$$\frac{dp[i]}{A[i]}=\frac{dp[j]*R[j]}{A[j]*R[j]+B[j]}+\frac{B[i]}{A[i]}*\frac{dp[j]}{A[j]*R[j]+B[j]}$$

再移一下:

$$\frac{dp[j]*R[j]}{A[j]*R[j]+B[j]}=-\frac{B[i]}{A[i]}*\frac{dp[j]}{A[j]*R[j]+B[j]}+\frac{dp[i]}{A[i]}$$

現在讓$b$項最大,維護斜率遞減的上凸包。

但是x沒有單調性啊……

於是就有兩種處理方法。

第一種是$splay$線上強插,比較噁心;

第二種是$cdq$離線處理,非常好寫。

由於我們要儘可能優化時間,可以考慮每次更新之前讓左區間的$x$有序,右區間的$k$有序。

這樣的話左邊$O(n)$建凸包,右邊$O(n)$匹配。

但是每次都要排序啊……

我們不妨先將整個區間關於$k$排序,然後分治前按編號分好,這樣可以保證右邊的k一定是單調的。

這樣整體就是$O(nlogn)$了。

程式碼:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define db double
#define N 100050
const db eps = 1e-8;
const db inf = 1e10;
int n;
db dp[N];
struct node
{
    db a,b,r,x,y,k;
    int id;
}p[N],tmp[N];
db slop(node n1,node n2)
{
    
if(fabs(n1.x-n2.x)<=eps)return inf; return (n1.y-n2.y)/(n1.x-n2.x); } bool cmpid(node n1,node n2) { return n1.id<n2.id; } bool cmpk(node n1,node n2) { return n1.k<n2.k; } void Sort(int l,int r)//cmp x { int mid = (l+r)>>1; int i=l,j = mid+1,k = l-1; while(i<=mid&&j<=r) { while(i<=mid&&p[i].x<=p[j].x)tmp[++k]=p[i++]; while(j<=r&&p[i].x>p[j].x)tmp[++k]=p[j++]; } while(i<=mid)tmp[++k]=p[i++]; while(j<=r)tmp[++k]=p[j++]; for(i=l;i<=r;i++)p[i]=tmp[i]; } void divi(int l,int r) { int mid = (l+r)>>1; int i=l-1,j=mid; for(int k=l;k<=r;k++) { if(p[k].id<=mid)tmp[++i]=p[k]; else tmp[++j]=p[k]; } for(int k=l;k<=r;k++)p[k]=tmp[k]; } int sta[N],tl; void cdq(int l,int r) { if(l==r) { dp[l] = max(dp[l],dp[l-1]); p[l].x = dp[l]/(p[l].a*p[l].r+p[l].b); p[l].y = p[l].x*p[l].r; return ; } int mid = (l+r)>>1; divi(l,r); cdq(l,mid); tl = 0; for(int i=l;i<=mid;i++) { while(tl>=2&&slop(p[sta[tl]],p[i])+eps>slop(p[sta[tl]],p[sta[tl-1]]))tl--; sta[++tl] = i; } for(int i=mid+1;i<=r;i++) { while(tl>=2&&slop(p[sta[tl]],p[sta[tl-1]])<p[i].k+eps)tl--; dp[p[i].id] = max(dp[p[i].id],p[sta[tl]].x*p[i].b+p[sta[tl]].y*p[i].a); } cdq(mid+1,r); Sort(l,r); } int main() { scanf("%d%lf",&n,&dp[0]); for(int i=1;i<=n;i++) { scanf("%lf%lf%lf",&p[i].a,&p[i].b,&p[i].r); p[i].k = -p[i].b/p[i].a;p[i].id = i; } sort(p+1,p+1+n,cmpk); cdq(1,n); printf("%.3lf\n",dp[n]); return 0; }