J、旅店的小小死神
赛中没调出来~
Problem:
题意大概:白天和晚上分别有两次操作,白天:召唤+炼金or炼金+炼金,晚上:收集+炼金or炼金+炼金。(具体内容看题,不做赘述),求n天内收集到的灵魂最多数量
Ideas:
时间复杂度:o(logn)
我的做法是二分找答案,但是可以直接暴力,这里放上我的思路
分两种情况讨论:
- c * 4 <= a * x + 2 * c
- c * 4 > a * x + 2 * c
然后分别进行操作,第一种情况直接让白天都召唤+炼金,晚上收集+炼金即可
第二种情况需要前期白天召唤+炼金,晚上收集+炼金,后期只管炼金+炼金
主要是第二种做法:
通过二分去找答案,找到能够满足收集到的灵魂够后面使用的临界,然后再分别讨论该临界和比他小一的情况(完全利用残魂)
这里放代码
Code:
#include <bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int N = 1e5 + 10;
typedef pair<int, int> PII;
void solve() {
int x, a, b, c, n;
cin >> x >> a >> b >> c >> n;
int res = 0;
if(c * 4 <= a * x + 2 * c) { // 够数但没必要
res += (a * x + 2 * c) * n; // 每天都要用客户
res -= c; // 第一天白天没残魂
/* 该代码是暴力跑,按照题目意思 ,得使用__int128*/
// __int128 sum = 0;
// res = 0;
// for(int i = 0; i < n; i++) {
// if(sum >= c) res += c, sum -= c;
// sum += a * x * b;
// res += a * x;
// if(sum >= c) res += c, sum -= c;
// }
}
else { // 够数且有必要
int res1 = 0;
int l = 1, r = n; // 二分找答案(什么时候能够收集到后面都足够的灵魂)
while(l < r) {
int mid = l + r >> 1;
if((a * x * b - 2 * c) * mid + c >= 4 * c * (n - mid)) r = mid;
else l = mid + 1;
}
/* 前期正常用客户,后期只用残魂 */
res += 4 * (n - l) * c;
res += 2 * c * l - c + a * x * l;
/* 考虑到有可能少收集一天但是能够让残魂利用率最大化 */
l--;
res = max(res, l * a * x + (2 * l - 1) * c + min((n - l) * 4 * c, a * b * x * l - (2 * l - 1) * c));
}
cout << res << endl;
}
signed main()
{
ios::sync_with_stdio(false), cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--) {
solve();
}
}