货币系统(二分)
problem
【題目描述】
你在 NOIP 2018 的賽場(chǎng)上遇到了「貨幣系統(tǒng)」一題。你沒(méi)有寫出這題,導(dǎo)致網(wǎng)友的國(guó)度簡(jiǎn)化貨幣系統(tǒng)的任務(wù)失敗了。網(wǎng)友的國(guó)度的貨幣系統(tǒng)現(xiàn)在十分混亂。
網(wǎng)友的國(guó)度現(xiàn)今有兩套貨幣系統(tǒng)「忘憂」和「網(wǎng)游」。為了方便使用,它們有一個(gè)共用的貨幣單位「𰻞」,而且二者都可以湊出價(jià)值任意整數(shù)𰻞的貨幣。
你現(xiàn)在希望用人民幣來(lái)兌換一些網(wǎng)友的國(guó)度的貨幣。你需要兌換多次,每次恰好兌換 1 𰻞。
忘憂和網(wǎng)游的匯率互相獨(dú)立,而且會(huì)動(dòng)態(tài)改變。具體而言:
- 第一次兌換忘憂,1 𰻞花費(fèi) a 元;由于網(wǎng)友的國(guó)度持有的忘憂變少了,因此其價(jià)格
上漲:每?jī)稉Q 1 𰻞,下一𰻞的價(jià)格漲價(jià) b 元;
形式化地,第 i 次兌換忘憂的價(jià)格是一𰻞 b(i ?1) + a 元。 - 第一次兌換網(wǎng)游,1 𰻞花費(fèi) c 元;由于網(wǎng)友的國(guó)度持有的網(wǎng)游變少了,因此其價(jià)格上漲:每?jī)稉Q 1 𰻞,下一𰻞的價(jià)格漲價(jià) d 元;形式化地,第 i 次兌換網(wǎng)游的價(jià)格是一𰻞 d(i ?1) + c 元。
為了能夠隨機(jī)應(yīng)變,你希望提前知道給出的 q 種 a, b, c, d 下,用 x 元錢分別最多能兌換多少𰻞。
每次詢問(wèn)相互獨(dú)立
【輸入格式】
第一行一個(gè)正整數(shù) q,表示有 q 個(gè)詢問(wèn)。
接下來(lái) q 行,每行 5 個(gè)正整數(shù) a, b, c, d, x,分別表示忘憂、網(wǎng)游的匯率變化方式和你所擁有的錢。
【輸出格式】
輸出共 qqq 行,分別表示每次詢問(wèn)中你最多能兌換到多少𰻞。
1≤a,b,c,d,x≤1018,1≤q≤1051 ≤a, b, c, d, x ≤10^{18},1 ≤q ≤10^51≤a,b,c,d,x≤1018,1≤q≤105
solution
看到這種兩個(gè)函數(shù)都是單增的,且最后總限制為 xxx。
我就想到了 CSP-S 2021 T1,當(dāng)時(shí)我就是采取的三分騙到了不錯(cuò)的分?jǐn)?shù)。
這道題看起來(lái)似乎與二分/三分很有關(guān)聯(lián)。
但是這兩個(gè)函數(shù)不能拼成一個(gè)單調(diào)或有峰值的函數(shù),能夠直接做。
很妙的是,直接二分花費(fèi)最大值 midmidmid。
讓兩種物品的單個(gè)兌換最大花費(fèi)不超過(guò) midmidmid。
先計(jì)算出每種物品最多能買多少個(gè),最大的那個(gè)花費(fèi)不超過(guò) midmidmid,然后可以等差數(shù)列 O(1)O(1)O(1) 計(jì)算出。
具體而言,假設(shè)最多能買 iii 個(gè),即 b(i?1)+a≤midb(i-1)+a\le midb(i?1)+a≤mid。
花費(fèi)則為 ∑k=1ib(k?1)+a=∑k=1ibk+(a?b)?i=(b+b?i)i2+i?(a?b)\sum_{k=1}^ib(k-1)+a=\sum_{k=1}^ibk+(a-b)*i=\frac{(b+b*i)i}{2}+i*(a-b)∑k=1i?b(k?1)+a=∑k=1i?bk+(a?b)?i=2(b+b?i)i?+i?(a?b)。
再把兩種物品的花費(fèi)求和,與 xxx 限制比較。
當(dāng)然可能會(huì)剩下一點(diǎn) rrr,也許還可以再買兩種物品中的一個(gè),特判一下。
最開(kāi)始求最大花費(fèi)不超過(guò) midmidmid 的物品個(gè)數(shù)也請(qǐng)注意寫法。——來(lái)自傘兵博主。
code
#include <bits/stdc++.h> using namespace std; #define int __int128 int q, x, a, b, c, d, ans;void read( int &x ) {x = 0; char s = getchar();while( s < '0' or s > '9' ) s = getchar();while( '0' <= s and s <= '9' ) x = ( x << 1 ) + ( x << 3 ) + ( s - '0' ), s = getchar(); }void print( int x ) {if( x > 9 ) print( x / 10 );putchar( x % 10 + '0' ); }bool check( int v ) {int i = max( (int)0, ( v - a ) / b + 1 );int j = max( (int)0, ( v - c ) / d + 1 );if( i and b * ( i - 1 ) + a > v ) i --;if( j and d * ( j - 1 ) + c > v ) j --;int cost = ( i + 1 ) * b * i / 2 + i * ( a - b ) + ( j + 1 ) * d * j / 2 + j * ( c - d );if( cost > x ) return 0;int r = x - cost, tot = i + j;if( r >= b * i + a ) r -= b * i + a, tot ++, i ++;if( r >= d * j + c ) r -= d * j + c, tot ++, j ++;ans = max( ans, tot );return 1; }signed main() {freopen( "money.in", "r", stdin );freopen( "money.out", "w", stdout );read( q );while( q -- ) {read( a ), read( b ), read( c ), read( d ), read( x );int l = 0, r = x; ans = 0;while( l <= r ) {int mid = ( l + r ) / 2;if( check( mid ) ) l = mid + 1;else r = mid - 1;}print( ans );puts("");}return 0; }總結(jié)
- 上一篇: 帝国程序怎么重置id(帝国单机重置)
- 下一篇: java信息管理系统总结_java实现科