我解决的:K、B(得知算法后写出)、J(2 WA)。
没看的:D(不会做)。
我旁观的:A、C、H、I、G、E(我可能能做出来,但是估计要写一会)。
看了不会做的:F。
K Kleptography
简单题,略。我还想了一会才写出来,代码能力属实不行。
I Inflation
简单题,略。
H Hard Drive
应该是简单题?略。
J Jinxed Betting
题意(转化后):给定一些数,每次可以对这些数进行操作,一次操作为:设最大的数有 a a a 个,将最大的 ⌊ a 2 ⌋ \lfloor \frac{a}{2} \rfloor ⌊2a⌋ 个数,以及其他所有非最大的数均加 1。再给定一个目标 t t t,问至多操作几次,可以保证这些数中的最大者不超过 t t t。
手算一下可以发现,如果某一时刻最大的数 x 1 x_1 x1 有 a 1 a_1 a1 个,第二大的数 x 2 x_2 x2 有 a 2 a_2 a2 个,那么 ( x 1 − x 2 ) ( ⌊ log 2 a 1 ⌋ + 1 ) (x_1 - x_2) (\lfloor \log_2 a_1 \rfloor + 1) (x1−x2)(⌊log2a1⌋+1) 轮后最大的数变成了 a 1 + a 2 a_1 + a_2 a1+a2 个,即原本第二大的数全部长成了最大。
于是我们可以模拟这种合并的过程,通过一些简单的计算就可以得到答案。时间复杂度为 O ( n log n ) O(n \log n) O(nlogn),因为要排序。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
ll targ, a[100005];
stack<pair<ll, int> > st;
int logg[100005];
int main(){
scanf("%d%lld", &n, &targ);
--n;
for (int i = 1; i <= n; ++i)
scanf("%lld", &a[i]);
sort(a + 1, a + n + 1);
for (int i = 1, j; i <= n; i = j){
j = i;
while (j <= n && a[i] == a[j])
++j;
st.push(make_pair(a[i], j - i));
}
logg[1] = 1;
for (int i = 2; i <= n; ++i)
logg[i] = logg[i >> 1] + 1;
ll tot_round = 0;
// 由于不能批量加法,因此认为每一个数的实际值要加上 tot_round
while (st.size() > 1){
ll ori_x1 = st.top().first + tot_round, x1 = ori_x1;
int a1 = st.top().second;
st.pop();
ll x2 = st.top().first + tot_round;
int a2 = st.top().second;
st.pop();
ll round_needed = (x1 - x2) * logg[a1];
ll x1_added = round_needed - (x1 - x2);
x1 += x1_added;
if