A. Kevin and Arithmetic
题意:给你\(n\)个数,你一开始有一个\(x = 0\),每次你让\(x\)加上一个没用过的数,然后\(x\)会一直除二直到变成奇数。如果你加上一个数后能除2,分数加1,问分数最大多少。
奇数后面加奇数才能是偶数,但一开始\(x\)是零,那么需要一个偶数,否则只能浪费一个奇数。
所以如果有偶数就是奇数个数加1,否则是奇数个数减1.
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
int cnt[2]{};
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
++ cnt[a[i] & 1];
}
if (cnt[0]) {
std::cout << 1 + cnt[1] << "\n";
} else {
std::cout << std::max(0, cnt[1] - 1) << "\n";
}
}
B. Kevin and Geometry
题意:\(n\)个数,你要选四个数组成等腰梯形。
对梯形作高发现两边是两个三角形,那么(上底-下底)/2是底边长,为了让梯形的两个腰边能够上上底,这个距离一定小于腰边。所以我们找两个相同的数作为腰边,然后找差值最小的两个数当上底和下底。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<i64> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
std::sort(a.begin(), a.end());
int p = -1;
for (int i = 0; i + 1 < n; ++ i) {
if (a[i] == a[i + 1]) {
p = i;
break;
}
}
if (p == -1) {
std::cout << -1 << "\n";
return;
}
for (int i = 0, j = 0; i + 1 < n; ++ i) {
while (i == p || i == p + 1) {
++ i;
}
j = std::max(j, i);
while (j == i || j == p || j == p + 1) {
++ j;
}
if (i < n && j < n && std::abs(a[i] - a[j]) < a[p] + a[p]) {
std::cout << a[j] << " " << a[i] << " " << a[p] << " " << a[p] << "\n";
return;
}
}
std::cout << -1 << "\n";
}
C. Kevin and Puzzle
题意:\(n\)个人,每个人可能是老实人也可能是说谎者,老实人一定说真话。两个说谎者不能站一起。第\(i\)个说左边有\(a_i\)个骗子。问这些人可能的组合有多少。
\(f_{i_{0/1}}\)表示第\(i\)个是老实人/说谎者。那么如果\(i\)是老实人,看前面一个人怎么转移过来。如果前面那个人也是老实人,那么\(a_i = a_{i+1}\),因为\(i\)说真话,\(i-1\)也是老实人,那么\(i-1\)左边的老实人应该等于\(a_i\)说的,不然两个人不可能同时是老实人。如果\(i-1\)是说谎者,那么因为两个说谎者不能站一起,第\(i-2\)个人一定是老实人,因为\(i-1\)是说谎者,那么到\(i-2\)这里还有\(a_i - 1\)个说谎者,看能不能对上就行。
如果\(i\)说谎,那么\(i-1\)一定使老实人,\(f_{i_0} = f_{i-1_1}\)。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n + 1);
for (int i = 1; i <= n; ++ i) {
std::cin >> a[i];
}
if (n == 1) {
std::cout << (1 + (a[1] == 0)) << "\n";
return;
}
std::vector f(n + 1, std::array<Z, 2>{});
f[1][0] = a[1] == 0;
f[1][1] = 1;
for (int i = 2; i <= n; ++ i) {
if (a[i] == a[i - 1]) {
f[i][0] += f[i - 1][0];
}
if (i >= 2 && a[i] - 1 == a[i - 2]) {
f[i][0] += f[i - 1][1];
}
f[i][1] = f[i - 1][0];
}
std::cout << f[n][0] + f[n][1] << "\n";
}
D. Kevin and Numbers
题意:两个数字\(A\)和\(B\),每次可以从\(A\)里选两个数,满足他们的差绝对值小于等于1,然后把这两个数删掉,然后把他们的和加入\(A\),问\(A\)能不能变成\(B\)。
考虑反着来,从\(B\)到\(A\),那么发现如果\(B\)的最大值大于\(A\)的最大值,那么这个最大值必须拆开,发现拆开的方式是唯一的。于是模拟就行。
注意最多操作\(n-m\)次,一直操作可能超时。
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::priority_queue<int> a, b;
for (int i = 0; i < n; ++ i) {
int x;
std::cin >> x;
a.push(x);
}
for (int i = 0; i < m; ++ i) {
int x;
std::cin >> x;
b.push(x);
}
i64 sum = n - m;
while (sum >= 0 && a.size() && b.size()) {
if (a.top() == b.top()) {
a.pop();
b.pop();
} else if (sum > 0) {
int u = b.top(); b.pop();
b.push(u / 2);
b.push(u - u / 2);
-- sum;
} else {
break;
}
}
if (a.empty() && b.empty()) {
std::cout << "YES\n";
} else {
std::cout << "NO\n";
}
}
E. Kevin and And
题意:\(n\)个数,你有\(m\)个数让他们操作,每次可以选一个\(i\)和\(j\),然后\(a_i \&= b_j\),求最多\(k\)次操作让数组和最小。
发现\(m\)很小,枚举所有操作可以与的数。 然后计算\(f_{ij}\)表示第\(a_i\)操作\(j\)次最多减小多少,然后差分一下,记\(d_{i,j}\)为\(a_i\)操作\(j\)次比操作\(j-1\)次可以多减少的值。就可以用优先级队列记录一次操作可以减少的最大值。
点击查看代码
void solve() {
int n, m, k;
std::cin >> n >> m >> k;
std::vector<i64> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
std::vector<i64> b(m);
for (int i = 0; i < m; ++ i) {
std::cin >> b[i];
}
std::vector<std::vector<i64> > op(m + 1);
for (int i = 0; i < 1 << m; ++ i) {
i64 x = (1ll << 30) - 1;
int cnt = 0;
for (int j = 0; j < m; ++ j) {
if (i >> j & 1) {
x &= b[j];
++ cnt;
}
}
op[cnt].push_back(x);
}
std::vector d(n, std::vector<i64>(m + 1));
for (int i = 0; i < n; ++ i) {
for (int j = 1; j <= m; ++ j) {
for (auto & x : op[j]) {
d[i][j] = std::max(d[i][j], a[i] - (a[i] & x));
}
d[i][j] = std::max(d[i][j], d[i][j - 1]);
}
for (int j = m; j >= 1; -- j) {
d[i][j] = d[i][j] - d[i][j - 1];
}
}
std::priority_queue<std::array<i64, 3> > heap;
for (int i = 0; i < n; ++ i) {
heap.push({d[i][1], 1, i});
}
i64 ans = std::accumulate(a.begin(), a.end(), 0ll);
while (k -- ) {
auto [x, cnt, id] = heap.top(); heap.pop();
ans -= x;
if (cnt + 1 <= m) {
heap.push({d[id][cnt + 1], cnt + 1, id});
}
}
std::cout << ans << "\n";
}