初始時有\(m\)的本金,已經知道之後\(n\)天內每一天\(a\)券與\(b\)券的價值,每一天可以**或賣出金券。
賣出金券方法如下:自己提供乙個\([0,100]\)內的實數\(op\),意義為將\(op\%\)的\(a\)券和\(op\%\)的\(b\)券賣出。
**金券方法如下:每一天給定乙個\(r\),自己給出乙個**的金額\(ip\),滿足**\(a\)券與\(b\)券數量之比為\(r\),總價值為\(op\)。
求\(n\)天後擁有的最大總價值。
首先不難想到乙個這樣的策略,賣出金券時,一定全部賣出是最優的,這個感覺比較顯然,有了這個,\(op\)的限制就不存在了。
考慮dp,我們可以得到乙個這樣的轉移方程:
\(dp_i=\max(dp_,\max\limits_^\)\),其中\(x_i=\frac,y_i=\frac\)。
表示第\(i\)天不操作,或者把第\(j\)天**的金券全部賣出的最大價值。這是乙個\(o(n^2)\)的演算法,能拿到60pts。
考慮如何去優化,看見式子中含與\(i,j\)有關部分之積\(a_i \times dp_j\),發現這是乙個典型的斜率優化。
忽略掉\(\max\)符號,改寫一下式子:\(y_j=-\fracx_j+\frac\),斜率已知,目標是最大化截距,可以維護乙個上凸殼。
但是,我們發現每一次加入的點\((x_i,y_i)\)無論在橫座標上還是縱座標上都不單調,無法簡單的用單調佇列維護,於是考慮用平衡樹動態維護凸殼,來實現在任意位置插入及刪除,總複雜度\(o(nlogn)\)。
#include#define eps 1e-8
#define db double
using namespace std;
int n,m;
db dp[100005];
db a[100005],b[100005],r[100005],x[100005],y[100005];
struct splay
inline db slope(int a,int b)
}
return;
}int findpre(int x)
else
now=son[now][0];
}return ans;
} int findsuf(int x)
else
now=son[now][1];
}return ans;
}void add(int x)
else
lk[x]=+dbl_max;
if(son[x][1])
else
rk[x]=-dbl_max;
if(lk[x]+eps<=rk[x])
return;
}int find(db k)
return 0;
} }t;int main()
dp[0]=m;
for(register int i=1;i<=n;++i)
printf("%0.3lf\n",dp[n]);
return 0;
}
NOI2007 貨幣兌換
今天聽了crazy和samjia的noi雜 砸 題選講,感覺自己萌萌噠 於是就來怡情地寫了這道題。額 o 這個不好說啊。語文不好不好裱我 還是貼圖吧。咳咳,希望大家都看懂題了。乙個很明顯的貪心思路就是,我們每天要不全買,要不全賣。因為一有利益我們就去佔,一有虧損我們就不碰。那麼我們可以有dp方程 f...
Noi2007 貨幣兌換
傳送門 小半個上午 一下午都給了這題了qaq 都知道是斜率優化,問題是我看這題根本就是乙個人乙個式子啊 算了,把我的過程列出來吧 令 f i 表示第i天結束時強制賣出所有金券最多能得到的軟妹幣數量,列舉上一次 金券的時間,就有 beginf i max end 這裡沒有寫隱含條件 f i ge f ...
NOI2007 貨幣兌換
題目 先來畫一畫柿子 設 dp i 表示你第 i 天之後最多剩下多少錢 考慮一下對於 i 的轉移,我們肯定要在之前列舉一天 j 這一天把所有的東西買進來,之後在 i 天賣掉 設那天買進 a 的量為 d a 買進 b 的量為 d b 我們可以得到這樣的方程 d ap a d bp b dp j d a...