BZOJ1492: [NOI2007]货币兑换Cash

1492: [NOI2007]货币兑换Cash

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 1556  Solved: 724
[Submit][Status]

Description

小 Y 最近在一家金券交易所工作。该金券交易所只发行交易两种金券:A 纪
念券(以下简称 A 券)和 B 纪念券(以下简称 B 券)。每个持有金券的顾客都有
一个自己的帐户。金券的数目可以是一个实数。
每天随着市场的起伏波动,两种金券都有自己当时的价值,即每一单位金券
当天可以兑换的人民币数目。我们记录第 K 天中 A 券和 B 券的价值分别为 AK和
BK(元/单位金券)。
为了方便顾客,金券交易所提供了一种非常方便的交易方式:比例交易法。
比例交易法分为两个方面:
a)
卖出金券:顾客提供一个[0,100]内的实数 OP 作为卖出比例,其意
义为:将 OP%的 A 券和 OP%的 B 券以当时的价值兑换为人民币;
b)
买入金券:顾客支付 IP 元人民币,交易所将会兑换给用户总价值为
IP 的金券,并且,满足提供给顾客的 A 券和 B 券的比例在第 K 天恰好为 RateK;

Input

第一行两个正整数N、S,分别表示小Y 能预知的天数以及初始时拥有的钱数。 接下来N 行,第K 行三个实数AK、BK、RateK,意义如题目中所述

Output

只有一个实数MaxProfit,表示第N 天的操作结束时能够获得的最大的金钱 数目。答案保留3 位小数。

Sample Input

3 100
1 1 1
1 2 2
2 2 3

Sample Output

225.000

HINT


测试数据设计使得精度误差不会超过10-7。
对于40%的测试数据,满足N ≤ 10;
对于60%的测试数据,满足N ≤ 1 000;
对于100%的测试数据,满足N ≤ 100 000;

Source

题解:

CDQ分治说起来容易,写起来也不容易。。。

它之所以能够保持O(n*logn)的复杂度 是因为 T(n)=2*T(n/2)+O(n) 的解为 T(n)=n*logn

所以 在计算 l--mid  对 mid+1--r 的影响时所有的操作时间都必须是线性的

所以 在 合并的时候 我们要求

1.求凸包不需要排序

2.询问 k 单调,只需用单调队列

要解决第一点,我们只需要 按归并排序的思想每次递归调用结束时 merge l--r 即可

要解决第二点,我们需要预处理对k排序,使得在solve分治的时候 ,直接分到mid+1 --r的k是有序的,尽管序号可能并不是连续的,但这不影响答案

这是一个优美的算法。

代码:

1.我找的代码

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cmath>
  5 #include<cstring>
  6 #define maxn 120000
  7 #define eps 1e-9
  8 #define inf 1e9
  9 using namespace std;
 10 struct query
 11 {
 12     double q,a,b,rate,k;
 13     int pos;
 14 }q[maxn],nq[maxn];
 15 double fabs(double x)
 16 {
 17     return (x>0)?x:-x;
 18 }
 19 struct point
 20 {
 21     double x,y;
 22     friend bool operator <(const point &a,const point &b) 
 23     {    
 24         return (a.x<b.x+eps)||(fabs(a.x-b.x)<=eps&&a.y<b.y+eps);
 25     }
 26 }p[maxn],np[maxn];
 27 int st[maxn];
 28 double f[maxn];
 29 int n,m;
 30 
 31 double getk(int i,int j)
 32 {
 33     if (i==0) return -inf;
 34     if (j==0) return inf;
 35     if (fabs(p[i].x-p[j].x)<=eps) return -inf;
 36     return (p[i].y-p[j].y)/(p[i].x-p[j].x);
 37 }
 38 
 39 void solve(int l,int r)
 40 {
 41     if (l==r)//此时l之前包括l的f值已经达到最优,计算出对应的点即可
 42     {
 43         f[l]=max(f[l-1],f[l]);
 44         p[l].y=f[l]/(q[l].a*q[l].rate+q[l].b);
 45         p[l].x=p[l].y*q[l].rate;
 46         return ;
 47     }
 48     int mid=(l+r)>>1,l1=l,l2=mid+1;
 49     //对询问集合排序,1位置2斜率
 50     for (int i=l;i<=r;i++)
 51         if (q[i].pos<=mid) nq[l1++]=q[i];
 52         else nq[l2++]=q[i];
 53     for (int i=l;i<=r;i++) q[i]=nq[i];
 54     //递归左区间
 55     solve(l,mid);
 56     //左半区所有点都以计算好,把它们入栈,维护凸壳
 57     int top=0;
 58     for (int i=l;i<=mid;i++)
 59     {
 60         while (top>=2&&getk(i,st[top])+eps>getk(st[top],st[top-1])) top--;
 61         st[++top]=i;
 62     }
 63     //拿左半区更新右半区
 64     int j=1;
 65     for (int i=r;i>=mid+1;i--)//保证询问斜率递减
 66     {
 67         while (j<top&&q[i].k<getk(st[j],st[j+1])+eps) j++;
 68         f[q[i].pos]=max(f[q[i].pos],p[st[j]].x*q[i].a+p[st[j]].y*q[i].b);
 69     }        
 70     //递归右区间
 71     solve(mid+1,r);
 72     //合并左右区间的点,按照x,y排序
 73     l1=l,l2=mid+1;
 74     for (int i=l;i<=r;i++)
 75         if ((p[l1]<p[l2]||l2>r)&&l1<=mid) np[i]=p[l1++];
 76         else np[i]=p[l2++];
 77     for (int i=l;i<=r;i++) p[i]=np[i];
 78 }
 79 
 80 bool cmp(query a,query b)
 81 {
 82     return a.k<b.k;
 83 }
 84 
 85 int main()
 86 {
 87     freopen("input.txt","r",stdin);
 88     freopen("output2.txt","w",stdout);
 89     scanf("%d%lf",&n,&f[0]);
 90     for (int i=1;i<=n;i++)
 91     {
 92         scanf("%lf%lf%lf",&q[i].a,&q[i].b,&q[i].rate);
 93         q[i].k=-q[i].a/q[i].b;
 94         q[i].pos=i;
 95     }
 96     sort(q+1,q+n+1,cmp);
 97     solve(1,n);
 98     //for(int i=1;i<=n;i++)cout<<i<<' '<<f[i]<<endl;
 99     printf("%.3lf\n",f[n]);
100     return 0;
101 }
View Code

2.我的代码(基本一样。。。都是抄的。。。)

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<iostream>
 7 #include<vector>
 8 #include<map>
 9 #include<set>
10 #include<queue>
11 #define inf 1000000000
12 #define maxn 100000+1000
13 #define maxm 500+100
14 #define eps 1e-10
15 #define ll long long
16 #define pa pair<int,int>
17 using namespace std;
18 struct rec{double a,b,rate,k;int id;}q[maxn],nq[maxn];
19 struct point
20 {
21     double x,y;
22     friend bool operator <(const point &a,const point &b)
23     {
24         return (a.x<b.x+eps||(fabs(a.x-b.x)<eps&&a.y<b.y+eps));
25     }
26 }p[maxn],np[maxn];
27 double f[maxn];
28 int sta[maxn],n;
29 double getk(int i,int j)
30 {
31     if(!i)return -inf;
32     if(!j)return inf;
33     if(fabs(p[i].x-p[j].x)<=eps)return -inf;
34     return (p[i].y-p[j].y)/(p[i].x-p[j].x);
35 }
36 void solve(int l,int r)
37 {
38    if(l==r)
39    {
40        f[l]=max(f[l],f[l-1]);
41        p[l].y=f[l]/(q[l].a*q[l].rate+q[l].b);
42        p[l].x=p[l].y*q[l].rate;
43        return;
44    }    
45    int mid=(l+r)>>1,l1=l,l2=mid+1;
46    for(int i=l;i<=r;i++)
47     if(q[i].id<=mid)nq[l1++]=q[i];else nq[l2++]=q[i];
48    for(int i=l;i<=r;i++)q[i]=nq[i];
49    solve(l,mid);
50    int top=0;
51    for(int i=l;i<=mid;i++)
52    {
53        while(top>=2&&getk(i,sta[top])+eps>getk(sta[top],sta[top-1]))top--;
54        sta[++top]=i;
55    } 
56    int j=1;
57    for(int i=r;i>=mid+1;i--)
58    {
59        while(j<top&&q[i].k<getk(sta[j],sta[j+1])+eps)j++;
60        f[q[i].id]=max(f[q[i].id],p[sta[j]].x*q[i].a+p[sta[j]].y*q[i].b);
61    }
62    solve(mid+1,r);
63    l1=l;l2=mid+1;
64    for(int i=l;i<=r;i++)
65    if((p[l1]<p[l2]||l2>r)&&l1<=mid)np[i]=p[l1++];else np[i]=p[l2++];
66    for(int i=l;i<=r;i++)p[i]=np[i];
67 }
68 bool cmp(rec a,rec b)
69 {
70     return a.k<b.k;
71 }
72 int main()
73 {
74     freopen("input.txt","r",stdin);
75     freopen("output.txt","w",stdout);
76     scanf("%d%lf",&n,&f[0]);
77     for(int i=1;i<=n;i++)
78      {
79       scanf("%lf%lf%lf",&q[i].a,&q[i].b,&q[i].rate);
80       q[i].k=-q[i].a/q[i].b;
81       q[i].id=i;
82      }
83     sort(q+1,q+n+1,cmp);
84     solve(1,n);
85     //for(int i=1;i<=n;i++)cout<<i<<' '<<f[i]<<endl;
86     printf("%.3lf\n",f[n]);
87     return 0; 
88 }
View Code

 

posted @ 2014-08-27 00:07  ZYF-ZYF  Views(284)  Comments(1Edit  收藏  举报