货币系统(二分)
problem
【題目描述】
你在 NOIP 2018 的賽場上遇到了「貨幣系統」一題。你沒有寫出這題,導致網友的國度簡化貨幣系統的任務失敗了。網友的國度的貨幣系統現在十分混亂。
網友的國度現今有兩套貨幣系統「忘憂」和「網游」。為了方便使用,它們有一個共用的貨幣單位「𰻞」,而且二者都可以湊出價值任意整數𰻞的貨幣。
你現在希望用人民幣來兌換一些網友的國度的貨幣。你需要兌換多次,每次恰好兌換 1 𰻞。
忘憂和網游的匯率互相獨立,而且會動態改變。具體而言:
- 第一次兌換忘憂,1 𰻞花費 a 元;由于網友的國度持有的忘憂變少了,因此其價格
上漲:每兌換 1 𰻞,下一𰻞的價格漲價 b 元;
形式化地,第 i 次兌換忘憂的價格是一𰻞 b(i ?1) + a 元。 - 第一次兌換網游,1 𰻞花費 c 元;由于網友的國度持有的網游變少了,因此其價格上漲:每兌換 1 𰻞,下一𰻞的價格漲價 d 元;形式化地,第 i 次兌換網游的價格是一𰻞 d(i ?1) + c 元。
為了能夠隨機應變,你希望提前知道給出的 q 種 a, b, c, d 下,用 x 元錢分別最多能兌換多少𰻞。
每次詢問相互獨立
【輸入格式】
第一行一個正整數 q,表示有 q 個詢問。
接下來 q 行,每行 5 個正整數 a, b, c, d, x,分別表示忘憂、網游的匯率變化方式和你所擁有的錢。
【輸出格式】
輸出共 qqq 行,分別表示每次詢問中你最多能兌換到多少𰻞。
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
看到這種兩個函數都是單增的,且最后總限制為 xxx。
我就想到了 CSP-S 2021 T1,當時我就是采取的三分騙到了不錯的分數。
這道題看起來似乎與二分/三分很有關聯。
但是這兩個函數不能拼成一個單調或有峰值的函數,能夠直接做。
很妙的是,直接二分花費最大值 midmidmid。
讓兩種物品的單個兌換最大花費不超過 midmidmid。
先計算出每種物品最多能買多少個,最大的那個花費不超過 midmidmid,然后可以等差數列 O(1)O(1)O(1) 計算出。
具體而言,假設最多能買 iii 個,即 b(i?1)+a≤midb(i-1)+a\le midb(i?1)+a≤mid。
花費則為 ∑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)。
再把兩種物品的花費求和,與 xxx 限制比較。
當然可能會剩下一點 rrr,也許還可以再買兩種物品中的一個,特判一下。
最開始求最大花費不超過 midmidmid 的物品個數也請注意寫法。——來自傘兵博主。
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; }總結
- 上一篇: 帝国程序怎么重置id(帝国单机重置)
- 下一篇: 怎么解绑辅助账号(怎么解绑辅助账号手机)