- 寫在前面
- A
- B
- C
- D
- E
- 寫在最後
寫在前面
比賽地址:https://codeforces.com/contest/1990
依舊是紅溫溫溫溫溫溫溫溫溫溫場。
AB 每題都吃了兩發,爽!D 到最後也沒調出來賽後五分鐘看出來哪掛了,爽!又要掉一百分了,爽!
所有錯誤都是每題多看兩眼就能找到的但就是沒多看兩眼。
媽的傻逼一天天的在這幹啥啊、、、急成這個逼樣子還是急著投胎算了。
A
手玩。
操作等價於選擇某個權值的第一個數,並將在此之前所有數全部刪除。
先考慮只有一種權值的情況。顯然此時若 \(n\) 為奇數,則先手必勝,否則先手必敗。
然後考慮多種權值。發現若所有權值的出現次數均為偶數,則先手必敗,否則先手僅需選擇最大的出現次數為奇數的權值,即可令後手進入必敗狀態。
於是僅需檢查是否有一種權值出現次數為奇數即可。
//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
//=============================================================
//=============================================================
//=============================================================
int main() {
//freopen("1.txt", "r", stdin);
std::ios::sync_with_stdio(0), std::cin.tie(0);
int T; std::cin >> T;
while (T --) {
int n; std::cin >> n;
int cnt[100] = {0};
for (int i = 1; i <= n; ++ i) {
int a; std::cin >> a;
++ cnt[a];
}
int flag = 0;
for (int i = n; i; -- i) {
if (cnt[i] % 2 == 1) flag = 1;
}
std::cout << (flag ? "YES\n" : "NO\n");
}
return 0;
}
B
構造。
顯然應令 \([y, x]\) 內全部為 1,\(y - 1, x + 1\) 均為 -1。然後考慮令 \([1, y - 1]\) 和 \([x + 1, n]\) 的前字尾和均儘可能地小以符合題意。
發現僅需從 \(y - 1, x + 1\) 開始,分別向左右構造成 -1/1 交替的形式即可。此時 \([1, y - 1]\) 和 \([x + 1, n]\) 的任意前字尾和均不大於 1。且若 \([1, y - 1]\) 存在字首和為 1 則 \([1, y-1]\) 和為 0;若 \([x+1, n]\) 存在字尾和為 1 則 \([x+1, n]\) 和為 0。而在 \([y, x]\) 內至少會獲得 +2 的貢獻,則上述構造一定合法。
//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 1e5 + 10;
//=============================================================
int n, x, y, ans[kN];
//=============================================================
//=============================================================
int main() {
//freopen("1.txt", "r", stdin);
std::ios::sync_with_stdio(0), std::cin.tie(0);
int T; std::cin >> T;
while (T --) {
std::cin >> n >> x >> y;
// int a = x - 1, b = y - x - 1, c = n - x;
ans[x] = ans[y] = 1;
for (int i = y; i <= x; ++ i) ans[i] = 1;
for (int i = y - 1, j = -1; i; -- i, j = -j) ans[i] = j;
for (int i = x + 1, j = -1; i <= n; ++ i, j = -j) ans[i] = j;
for (int i = 1; i <= n; ++ i) std::cout << ans[i] << " ";
std::cout << "\n";
}
return 0;
}
C
模擬,暴力。
先手玩一下。前兩次操作沒什麼規律,但發現從第二次操作開始,數列一定為單調遞增,且除了最大的權值外每種權值至少出現 2 次,且每次操作對數列的影響均為使數列整體右移一位,刪去最後一個數並在前面補 0。
於是先暴力模擬兩輪記錄貢獻和,然後求得每種權值的出現次數,再降序列舉每種權值(也即每輪刪數的順序),統計刪去該權值的各輪的貢獻之和即可。
總時間複雜度 \(O(n)\) 級別。
//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e5 + 10;
//=============================================================
int n, a[kN], cnt[kN];
LL ans;
//=============================================================
void solve() {
for (int i = 0; i <= n; ++ i) cnt[i] = 0;
int mad = 0;
for (int i = 1; i <= n; ++ i) {
ans += a[i];
++ cnt[a[i]];
if (cnt[a[i]] >= 2 && a[i] > mad) mad = a[i];
a[i] = mad;
}
}
LL sum(int L_, int R_) {
return 1ll * (L_ + R_) * (R_ - L_ + 1ll) / 2ll;
}
void solve1() {
LL delta = 0;
for (int i = 0; i <= n; ++ i) cnt[i] = 0;
for (int i = 1; i <= n; ++ i) delta += a[i], ++ cnt[a[i]];
for (int i = n; i; -- i) {
if (cnt[i] == 0) continue;
ans += 1ll * cnt[i] * delta - sum(1, cnt[i] - 1) * i;
delta -= 1ll * cnt[i] * i;
}
}
//=============================================================
int main() {
// freopen("1.txt", "r", stdin);
std::ios::sync_with_stdio(0), std::cin.tie(0);
int T; std::cin >> T;
while (T --) {
std::cin >> n;
ans = cnt[0] = 0;
for (int i = 1; i <= n; ++ i) {
std::cin >> a[i];
cnt[i] = 0;
}
solve();
solve();
solve1();
std::cout << ans << "\n";
}
return 0;
}
/*
1
3
2 2 3
*/
D
手玩,貪心。
發現使用 \(2\times 2\) 矩陣的操作 1 大部分情況下是不值的,對某兩行使用兩次操作 1 一定不優於兩次操作 2。
手玩下可以發現如下結論:
- 使用一次操作 2 等於對下方所有行消除之前進行的操作 1 的影響,於是僅需考慮每次連續使用操作 1 的影響。
- 使用操作 1 被覆蓋的行黑色數量一定不會大於 4,否則不優。
- 連續使用操作 1 時,若使用了 \(k\) 次則一定會使 \(k+1\) 行被全部覆蓋,否則不優。
- 連續使用操作 1 時,被覆蓋的第一行黑色數量一定不會大於 2,否則不優。
- 由結論 1234,連續使用操作 1 時,第一次操作 1 覆蓋的範圍一定是 \((x, 1), (x, 2)\),第二次一定是 \((x+1, 3), (x+1, 4)\),第三次一定是 \((x+2, 1), (x+2, 2)\),……直至第 \(x+k\) 行黑色數量大於 4,或使用操作 1 後無法覆蓋到第 \(x+k+1\) 行,此時對第 \(x+k\) 行進行一次操作 2 一定不會更劣。然後從第 \(x+k+1\) 行開始重複上述過程。
根據結論 45,僅需從第一行開始貪心地操作即可。若某行滿足進行第一次操作 1 的條件,則連續進行操作 1 直至不滿足條件,再換用一次操作 2,再從下一行開始重複上述過程。
//
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
const int kN = 2e5 + 10;
//=============================================================
int n, a[kN];
//=============================================================
int solve(int now_, int left_, int right_) {
if (now_ > n) return 0;
if (a[now_] <= 0) return solve(now_ + 1, 0, 0); //此行不需操作
if (a[now_] <= 2) {
if (left_) return solve(now_ + 1, 0, 0); //左側兩個已被覆蓋,則不需操作此行
return solve(now_ + 1, 1, 0) + 1; //對此行進行操作 1,不會更劣
}
if (a[now_] <= 4) {
if (right_) return solve(now_ + 1, 1, 0) + 1; //右側兩個已被覆蓋,對左側操作
if (left_) return solve(now_ + 1, 0, 1) + 1; //左側兩個已被覆蓋,對右側操作
//若無覆蓋,對此行操作 2,不會更劣。
}
return solve(now_ + 1, 0, 0) + 1; //此行操作 2
}
//=============================================================
int main() {
// freopen("1.txt", "r", stdin);
std::ios::sync_with_stdio(0), std::cin.tie(0);
int T; std::cin >> T;
while (T --) {
std::cin >> n;
for (int i = 1; i <= n; ++ i) std::cin >> a[i];
std::cout << solve(1, 0, 0) << "\n";
}
return 0;
}
/*
1
4
3 2 1 0
1
4
2 4 4 2
1
3
2 3 5
1
6
2 4 4 4 4 2
*/
E
互動,
寫在最後
學到了什麼:
- 急你馬呢
- 急你馬呢急你馬呢
- 急你馬呢急你馬呢急你馬呢
- 急你馬呢急你馬呢急你馬呢急你馬呢
- 急你馬呢急你馬呢急你馬呢急你馬呢急你馬呢
- 急你馬呢急你馬呢急你馬呢急你馬呢急你馬呢急你馬呢
- 急你馬呢急你馬呢急你馬呢急你馬呢急你馬呢急你馬呢急你馬呢
我操不想活了。