Codeforces Round 935 (Div. 3)(A-G)
题目链接:Codeforces Round 935 (Div. 3)
void solve(){ ll a, b, c; cin >> a >> b >> c; ll ans = a; ans += b / 3; b -= b / 3 * 3; if(b == 0) ans += c / 3 + (c % 3 != 0); else{ ll cha = 3 - b; if(cha > c) ans = -1; else{ c -= cha; ans ++; ans += c / 3 + (c % 3 != 0); } } cout << ans << '\n'; }
B. Fireworks
void solve(){ ll a, b, m; cin >> a >> b >> m; ll ans = m / a + 1; ans += m / b + 1; cout << ans << '\n'; }
C. Left and Right Houses
题意:有n间房子,要在最前方或者最后或者两间房子之间建立一条街道,标记为0的房子希望在街道左边,标记为1的希望在街道右边,求至少能满足街道两边各一半(向上取整)且最靠近中央的的街道(如果多个满足,取最小),街道的位置是它前一间房子的下标,特殊的最前面的街道为0
思路:求一下前缀1的数量,枚举每一个建造街道的点,用差分求出两边是否满足要求,最后取最靠近中点且最小的街道
void solve(){ int n; string s; cin >> n >> s; vector<ll> a(n + 1); for(int i = 1; i <= n; i ++){ if(s[i - 1] == '1'){ a[i] = 1; } } for(int i = 1; i <= n; i ++) a[i] += a[i - 1]; double n1 = n * 1.0; double ans = 1.0 * n1; int idx = 0; if(a[n] >= (n / 2 + (n % 2 != 0))){ ans = fabs(n1 / 2 - 0); idx = 0; } for(int i = 1; i <= n; i ++){ ll lsum = i - a[i], rsum = a[n] - a[i]; ll lp = i / 2 + (i % 2 != 0), rp = ((n - i) / 2 + ((n - i) % 2 != 0)); if(lsum >= lp && rsum >= rp){ // cout << i << '\n'; if(fabs(n1 / 2 - i * 1.0) < ans){ ans = fabs(n1 / 2 - i * 1.0); idx = i; } } } cout << idx << '\n'; }
D. Seraphim the Owl
思路:从后往前枚举,只在当前位取a[i],否则取min(a[i], b[i])
void solve(){ ll n, m; cin >> n >> m; vector<ll> a(n + 1), b(n + 1); for(int i = 1; i <= n; i ++) cin >> a[i]; for(int i = 1; i <= n; i ++) cin >> b[i]; ll ans = 1e18, sum = 0; for(int i = n; i >= 1; i --){ if(i <= m){ ll res = sum + a[i]; ans = min(ans, res); } sum = sum + min(a[i], b[i]); } cout << ans << '\n'; }
E. Binary Search
思路:按题意模拟二分,最后交换最终位置和目标答案的位置
void solve(){ ll n, x; cin >> n >> x; vector<ll> a(n + 1); int idx = 0; for(int i = 1; i <= n; i ++){ cin >> a[i]; if(a[i] == x) idx = i; } ll l = 1, r = n + 1; while(r - l != 1){ ll mid = r + l >> 1; if(a[mid] <= x) l = mid; else r = mid; } if(a[l] == x) cout << 0 << '\n'; else{ cout << 1 << '\n' << l << ' ' << idx << '\n'; } }
F. Kirill and Mushrooms
题意:每一朵蘑菇的价值为v[i],但是如果采n朵蘑菇,p[1]-p[n-1]的蘑菇都变成0(注意,这里不是p为1-(n-1)的蘑菇变为0,而是前n-1个p对应的位置变为0),同时,采得蘑菇的价值为采得蘑菇的数量和最小价值的蘑菇的价值的乘积
思路:先排序,从大到小来模拟,如何删除不合格的蘑菇,用set维护即可
void solve(){ ll n; cin >> n; vector<ll> a(n + 1), b(n + 1); for(int i = 1; i <= n; i ++) cin >> a[i]; for(int i = 1; i <= n; i ++) cin >> b[i]; set<PII> st; vector<PII> a1(n + 1); for(int i = 1; i <= n; i ++) a1[i] = {a[i], i}; sort(a1.begin() + 1, a1.end(), cmp); ll ans = 0, lens = 0; for(int i = 1; i <= n; i ++){ if(a[a1[i].second] == 0) continue; st.insert(a1[i]); int len = st.size(); if(len - 1 >= 1){ st.erase({a[b[len - 1]], b[len - 1]}); a[b[len - 1]] = 0; } int res = st.begin()->first * st.size(); if(res > ans){ ans = res; lens = st.size(); } else if(res == ans){ len = st.size(); lens = min(lens, len); } } cout << ans << ' ' << lens << '\n'; }
G. Cook and Porridge
题意:每个人有两个属性k和s,k是这个人排队的优先级,s是这个人完成一次行动后需要等待的时间,当一个人完成一次行动,就会进入等待,等待s之后重新进入队列,并且他会插到所有优先级比他低的人之前,求在d时间内所有人完成一次行动的最早时间,如果无法所有人都完成一次行动,输出-1
思路:一个大根堆维护当前正在排队的人,一个小根堆维护等待的人,先用后缀max保证初始排队的人是按照原来的顺序来的,接下来每次把大根堆顶拿出来,记录他是否喝过粥,同时把小根堆的等待完毕的人释放出来,最后如果在d时间内所有人都能喝过粥输出最后喝粥的人的时间,否则是-1
typedef tuple<int, int, int> TII;
void solve(){ int n, d; cin >> n >> d; vector<PII> a(n); for(auto & [x, y] : a) cin >> x >> y; priority_queue<TII> pq; pq.push({a[n - 1].first, -(n - 1), n - 1}); for(int i = n - 2, ma = a[n - 1].first; i >= 0; i --){ ma = max(ma, a[i].first); pq.push({ma, -i, i}); } priority_queue<TII, vector<TII>, greater<TII>> ret;//等待队列 vector<bool> vis(n); int num = 0, cnt = n + 1; for(int i = n + 1; i <= n + d; i ++){ auto [_, __, id] = pq.top(); pq.pop();//队首 if(!vis[id]) vis[id] = true, num ++; if(num == n){ cout << i - n << '\n'; return; } ret.push({i + a[id].second, a[id].second, id});//进入等待队列 while(get<0>(ret.top()) <= i){ auto [time, s, pid] = ret.top(); ret.pop(); pq.push({a[pid].first, -(cnt ++), pid}); } } cout << -1 << '\n'; }