Educational Codeforces Round 159 (Rated for Div. 2)

1|0基本情况

A题秒了。

B题想出来贪心思想,也想出来怎么找最优解了,但实现极其复杂繁琐,最后以先超时优化后又错误的结果告终。

2|0B. Getting Points

Problem - 1902B - Codeforces

明显越后面开始学收益越高。

然后写了个简单粗暴的纯模拟,T了。

#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using ll = long long; int T; ll n, l, t, p; int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout.tie(nullptr); std::cin >> T; while (T--) { ll sum = 0, cnt = 0; std::cin >> n >> p >> l >> t; ll tn = n; ll task = n / 7; if (n % 7 != 0) task = task + 1; while (n) { bool ok = false; int dy = (n % 7) ? (n % 7) : 7; int wk = n / 7; n -= dy; if (dy) wk = wk + 1; if (wk < 2) { for (int i = 1; i <= dy; i++) { if (task == 0) { sum += (dy - i + 1) * l; cnt += dy - i + 1; if (sum >= p) { while (sum - l >= p) { cnt--; sum -= l; } ok = true; } break; } sum += t + l; cnt++; if (sum >= p) { ok = true; break; } task--; } continue; } for (int i = 1; i <= dy; i++) { if (task >= 2) { sum += 2 * t + l; cnt++; if (sum >= p) { ok = true; break; } task -= 2; } else if (task >= 1) { sum += t + l; cnt++; if (sum >= p) { ok = true; break; } task -= 1; } else { sum += l * (dy - i + 1); cnt += dy - i + 1; if (sum >= p) { while (sum - l >= p) { cnt--; sum -= l; } ok = true; } break; } } if (ok) { break; } } std::cout << tn - cnt << std::endl; } return 0; }

然后就想着去掉循环的部分,全部用式子直接算,但是太多要处理的细节了,码力拉了。

#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using ll = long long; int T; ll n, l, t, p; int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout.tie(nullptr); std::cin >> T; while (T--) { std::cin >> n >> p >> l >> t; ll sum = 0, ans = 0; ll tDay = n; ll task = (n % 7 == 0) ? n / 7 : n / 7 + 1; int dy, wk; while (tDay != 0) { bool ok = false; if (tDay % 7 == 0) { dy = 7, wk = tDay / 7 + 1; } else { dy = tDay % 7, wk = tDay / 7; } tDay -= dy; if (wk == 1) { sum += t + dy * l; ans += dy; if (sum > p) { ans -= (sum - t - p) / l; sum -= sum - t - p; if (sum > p) { ans -= 1; } } continue; } if (task <= dy * 2) { int task_day = task / 2; if (task % 2 != 0) task_day++; int ntd = dy - task_day; sum += task * t + dy * l; ans += dy; if (sum >= p) { ok = true; if (sum > p) { if (sum - ntd * l <= p) { ans -= (sum - p) / l; } else { ans -= ntd; if (task % 2 == 0) ans -= (sum - p) / (l + t * 2); else { sum -= (t + l); ans -= 1; if (sum > p) { ans -= (sum - p) / (l + t * 2); } } } } break; } break; } else { task -= dy * 2; sum += dy * (l + t * 2); //printf("ans = %d, dy = %d\n", ans, dy); ans += dy; if (sum >= p) { ok = true; if (sum > p) { ans -= (sum - p) / (l + t * 2); } break; } } if (ok) break; } std::cout << n - ans << std::endl; } return 0; }

这题用二分答案简直轻松。

说白了,找最多休息天数,也就是找最少工作天数。

刚好符合二分答案最小的最大原则。(我居然没想到!)

直接二分最小天数 x,校验即可。

校验函数也很有说法:

bool check(ll x) { ll s = x * a + min(2 * x, (n + 6) / 7) * b; return s >= p; }

思路是直接课程的学分 x×a 再加上作业的学分 min((n+6)/7,2×x)×b 即可(如果作业数够就是 2×x,不然就是 (n+6)/7,即总周数,即刷出的总作业数。

我一开始觉得不严谨,万一周数为 1 要怎么特判呢,还有就是怎么保证这些作业都能做完呢。

后面仔细想想,每周才刷一个作业出来,作业量是远远小于天数的,是肯定可以保证写完的。

#include <bits/stdc++.h> using namespace std; #define ll long long #define MP make_pair ll n, p, a, b; bool check(ll x) { ll temp = x * a + min(x * 2, (n + 6) / 7) * b; return temp >= p; } void solve() { cin >> n >> p >> a >> b; ll l = 1, r = n, mid; while (l <= r) { mid = l + r >> 1; if (check(mid)) { r = mid - 1; } else { l = mid + 1; } } cout << n - l << endl; } int main() { ios::sync_with_stdio(false); int _; cin >> _; while (_--) solve(); }

__EOF__

本文作者Kdlyh
本文链接https://www.cnblogs.com/kdlyh/p/17875423.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   加固文明幻景  阅读(135)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示