using i128 = __int128; // 自定义int128输出,这道题不需要 // std::ostream &operator<<(std::ostream &os, i128 n) { // std::string s; // while (n) { // s += '0' + n % 10; // n /= 10; // } // std::reverse(s.begin(), s.end()); // return os << s; // }
/* 第 i 台打印机将重复进行以下工作计划:持续工作 ti × li 秒,然后停机 wi 秒 */
voidsolve(){ int n, k; cin >> n >> k; vector<int> t(n), l(n), w(n); for (int i = 0; i < n; ++i) { cin >> t[i] >> l[i] >> w[i]; } int left = 0, r = 2e18+5;
auto check = [&](int x)->bool{ i128 cnt = 0; for (int i = 0; i < n; ++i) { int temp = x / (t[i] * l[i] + w[i]); int rest = x - temp * (t[i] * l[i] + w[i]); if (rest > t[i]*l[i]) { cnt += (temp + 1) * l[i]; } else { cnt += temp * l[i] + rest / t[i]; } } return cnt >= k; };
while (left + 1 < r) { int mid = (left + r) >> 1ll; if (check(mid)) r = mid; else left = mid; } cout << left + 1 << endl; }
看范围T是500,其他都是1e9的范围,那么如果每轮能在根号范围内处理那么就是一个比较合理的处理,所以要考虑在暴力枚举的时候优化一些不必要重复的操作。注意到如果当前是买x袋面粉,那么如果想要买x+1袋面粉则可能需要跑好几轮,所以如果能计算出购买x袋面粉的轮次一定是一种优化,考虑极端情况是进行k种交易,那么假设买一次物品最少是2s,则有$ (1+2+…+k)\times2 \le t $,得出k大概是根号级别的,可以通过。
voidsolve(){ int p, a, b; int q, c, d; int m, t; cin >> p >> a >> b; cin >> q >> c >> d; cin >> m >> t; int rest = t; // 特判一次都不行的时候 if(m<p) return cout<<m<<endl,void(); while (true) { int x = m / p; int epo = ((x + 1) * p - m - 1) / ((q - p) * x) + 1; // 处理买m/p袋一共会跑几轮 epo = min(rest / (a*x + b + c*x + d), epo); m += epo*x*(q-p); rest -= epo*(a*x + b + c*x + d); // 一次都买不了就先结束 if(rest < (a*(x+1) + b + c*(x + 1) + d))break; } // 特判最后一轮 int maxn = (rest - b - d)/(a+c); m += max(maxn*(q-p),0ll); cout<<m<<endl; }