随笔 - 18  文章 - 0  评论 - 2  阅读 - 411

Codeforces 938 解题 Div 3

太久没做题了, 先拿个Div 3开刷。

Codeforces Round 938 Div 3:

A: 

首先我们可以发现到若2 * a <= b, 那么我们n >= 2 的时候,拿b是最优的。

若我们现在拿了许多的2以后, 我们还有余数 = 1, 我们就用a补上。

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 using i64 = long long;
 4 
 5 void solve() {
 6     int n, a, b; cin >> n >> a >> b;
 7     if (2 * a <= b) cout << n * a << '\n';
 8     else cout << (n / 2) * b + (n & 1) * a << '\n';
 9 }
10 int main() {
11     ios::sync_with_stdio(false);
12     cin.tie(nullptr); cout.tie(nullptr);
13 
14     int t; cin >> t;
15     while (t--) {
16         solve();
17     }
18 }
代码
复制代码

B:

B 非常简单就是求你的数和他的数是不是完全重合的。

我当时是直接用multiset来搞,没找到就是不一样,找到的话就移除掉一个数。

其实也可以直接推进一个vector 然后sort再一个一个对比。

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 using i64 = long long;
 4 
 5 void solve() {
 6     multiset<int> S;
 7     int n, c, d; cin >> n >> c >> d;
 8     int mn = 1E9 + 9;
 9     for (int i = 1; i <= n * n; i++) {
10         int x; cin >> x;
11         S.insert(x);
12         mn = min(mn, x);
13     }
14     bool ok = true;
15     for (int i = 1; i <= n; i++) {
16         int o = mn + (i - 1) * d;
17         for (int j = 1; j <= n; j++) {
18             int p = o + (j - 1) * c;
19             if (S.find(p) == S.end()) ok = false;
20             else S.erase(S.find(p));
21         }
22     }
23     if (ok) cout << "YES\n";
24     else cout << "NO\n";
25 }
26 int main() {
27     ios::sync_with_stdio(false);
28     cin.tie(nullptr); cout.tie(nullptr);
29 
30     int t; cin >> t;
31     while (t--) {
32         solve();
33     }
34 }
代码
复制代码

C:

C也是一眼的题。我们首先可以发现到前面的数承受了ceil(K / 2) (向上取整), 后面的数则是承受了 K / 2。

那么我们可以直接暴力这个承受伤害的过程。

我为了写代码方便我特判了一下当 K >= sum(A) 的情况。

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 using i64 = long long;
 4 
 5 void solve() {
 6     int n; i64 k; cin >> n >> k;
 7     vector<i64> a(n);
 8     for (int i = 0; i < n; i++) cin >> a[i];
 9     if (k >= accumulate(a.begin(), a.end(), 0LL)) {
10         cout << n << '\n';
11         return;
12     }
13     int p = 0; i64 rem = (k + 1) / 2;
14     while (rem) {
15         i64 use = min(rem, a[p]);
16         a[p] -= use;
17         rem -= use;
18         if (a[p] == 0) p++;
19     }
20     p = n - 1; rem = k / 2;
21     while (rem) {
22         i64 use = min(rem, a[p]);
23         a[p] -= use;
24         rem -= use;
25         if (a[p] == 0) p--;
26     }
27     int ans = 0;
28     for (int i = 0; i < n; i++) if (a[i] != 0) ans++;
29     cout << n - ans << '\n';
30 }
31 int main() {
32     ios::sync_with_stdio(false);
33     cin.tie(nullptr); cout.tie(nullptr);
34 
35     int t; cin >> t;
36     while (t--) {
37         solve();
38     }
39 }
代码
复制代码

D:

啊这题一看就感觉会了。

首先我们数字i的贡献其实就是min(ocA[i], ocB[i])。

ocA[i]表示i出现在A的次数, B相同。

那我们想要移除掉就减上以前的贡献,做出我们想要的改变, 再加上新的贡献。

那我们就可以算多少个i满足条件。

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 using i64 = long long;
 4 
 5 void solve() {
 6     int n, m, k; cin >> n >> m >> k;
 7     vector<int> a(n + 1), b(m + 1);
 8     for (int i = 1; i <= n; i++) cin >> a[i];
 9     for (int i = 1; i <= m; i++) cin >> b[i];
10     map<int,int> ocA, ocB;
11     for (int i = 1; i <= m; i++) ocB[b[i]]++;
12     int cur = 0;
13     function<void(int,int)> work = [&] (int x, int op) {
14         cur -= min(ocA[x], ocB[x]);
15         ocA[x] += op;
16         cur += min(ocA[x], ocB[x]);
17     };
18     int ans = 0;
19     for (int i = n; i >= 1; i--) {
20         if (i + m <= n) work(a[i + m], -1);
21         work(a[i], +1);
22         if (i <= n - m + 1 && cur >= k) ans++;
23     }
24     cout << ans << '\n';
25 }
26 int main() {
27     ios::sync_with_stdio(false);
28     cin.tie(nullptr); cout.tie(nullptr);
29 
30     int t; cin >> t;
31     while (t--) {
32         solve();
33     }
34 }
代码
复制代码

E:

首先看到我们可以做到O(N ^ 2)。

那么我们枚举从大到小,若当前的数满足条件,我们这不需要再继续往下搜了。

那么我们考虑怎么判断一个数行不行。让当前的x表示枚举的数。

我们从后面开始判断。若s[i]当前 = 0, 我们则需要反转他 (和前面的)。那么我们其实需要维护一个suffix sum来判断当前是否做了反转。

若我们的s[i] = 0, 且i < x, 那我们就可以说这一个数x不满足条件了。

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 using i64 = long long;
 4 
 5 void solve() {
 6     int n; cin >> n;
 7     string s; cin >> s;
 8     s = ' ' + s;
 9     function<bool(int)> work = [&] (int x) {
10         vector<int> suf(n + 1);
11         for (int i = n; i >= 1; i--) {
12             int o = s[i] - '0';
13             if (i + 1 <= n) suf[i] += suf[i + 1];
14             o += suf[i];
15             o %= 2;
16             if (o == 0) {
17                 suf[i]++;
18                 if (i - x >= 0) suf[i - x]--;
19                 else return false;
20             }
21         }
22         return true;
23     };
24     if (count(s.begin(), s.end(), '1') == n) {
25         cout << n << '\n';
26         return;
27     }
28     for (int i = n; i >= 1; i--) {
29         if (work(i)) {
30             cout << i << '\n';
31             return;
32         }
33     }
34     cout << 0 << '\n';
35 }
36 int main() {
37     ios::sync_with_stdio(false);
38     cin.tie(nullptr); cout.tie(nullptr);
39 
40     int t; cin >> t;
41     while (t--) {
42         solve();
43     }
44 }
代码
复制代码

F: 

这题不错虽然感觉没那么难。

首先我们可以看到当一个数的数量是偶数,他是没有贡献的。

那么我们可以打一个表来看什么时候我们xor = 0。

我们发现到我们要么是1, 2, 3, 4: 偶,偶,偶,偶, 要么是1, 2, 3, 4:奇,奇,奇,偶。

发现到其实若我们想要花费更加多的数来满足奇,奇,奇,偶的条件。

所以我们贪心取偶,偶,偶,偶。那么贡献就是 a/2 + b/2 + c/2 + d/2这样。

但是我们有可能最后有1, 1, 1, 0或者1, 1, 1, 1的数。那么我们在这个情况下取奇,奇,奇,偶,答案+1

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 using i64 = long long;
 4 
 5 void solve() {
 6     int a, b, c, d; 
 7     cin >> a >> b >> c >> d;
 8     int ans = (a / 2) + (b / 2) + (c / 2) + (d / 2);
 9     a %= 2; b %= 2; c %= 2; d %= 2;
10     if (a == 1 && b == 1 && c == 1) ans++;
11     cout << ans << '\n';
12     // all even or 1, 2, 3 is odd
13 }
14 int main() {
15     ios::sync_with_stdio(false);
16     cin.tie(nullptr); cout.tie(nullptr);
17 
18     int t; cin >> t;
19     while (t--) {
20         solve();
21     }
22 }
代码
复制代码

G: 

G有点傻了,不知道为什么vector开在function里面会爆。渍渍渍。

考虑枚举每一个数x是否可以到达(n, m)。首先我们让p[i][j] = a[i][j] % x 是不是 0。

然后呢,我们就可以非常简单的判断(i, j)是否可以被到达。这个应该不难。

现在发现到我们其实不需要枚举那么多数,我们枚举每个a[1][1]的因子就行。

我们直接sieve 然后暴力就可以。技术含量不高。

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 using i64 = long long;
 4 
 5 int gcd(int x, int y) {
 6     if (y == 0) return x;
 7     return gcd(y, x % y);
 8 }
 9 vector<int> _div[1000003];
10 void solve() {
11     int n, m; cin >> n >> m;
12     vector<vector<int>> a(n + 1, vector<int>(m + 1));
13     auto ok = a;
14     for (int i = 1; i <= n; i++) {
15         for (int j = 1; j <= m; j++) {
16             cin >> a[i][j];
17         }
18     }
19     auto work = [&](int x) {
20         for (int i = 1; i <= n; i++) {
21             for (int j = 1; j <= m; j++) {
22                 ok[i][j] = 0;
23             }
24         }
25         ok[1][1] = 1;
26         for (int i = 1; i <= n; i++) {
27             for (int j = 1; j <= m; j++) {
28                 if (a[i][j] % x) {
29                     ok[i][j] = 0;
30                     continue;
31                 }
32                 if (i - 1 >= 1) ok[i][j] |= ok[i - 1][j];
33                 if (j - 1 >= 1) ok[i][j] |= ok[i][j - 1];
34             }
35         }
36         return ok[n][m];
37     };
38     int ans = 1;
39     for (auto v : _div[a[1][1]]) if (work(v)) ans = max(ans, v); 
40     cout << ans << '\n';
41 }
42 int main() {
43     ios::sync_with_stdio(false);
44     cin.tie(nullptr); cout.tie(nullptr);
45 
46     for (int i = 1; i <= 1E6; i++) {
47         for (int j = i; j <= 1E6; j += i) {
48             _div[j].push_back(i);
49         }
50     }
51 
52     int t; cin >> t;
53     while (t--) {
54         solve();
55     }
56 }
代码
复制代码

H: 

一眼就知道R不能取值太高,直接暴力算R的上限 = 12。

那么我们就可以快乐的暴力算差值了。

我们枚举每个有塔的地方,让use[r] = 多了多少伤害 - 3 ^ r。

那么根据题目我们不能够拿同一个R,我们就可以维持一个dp[S] = 最高差值和,S在2进制表示第i个r有没有被使用了。

这就是什么bit DP。

答案就是dp里的最大值。

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 using i64 = long long;
 4 
 5 void solve() {
 6     int n, m, k; cin >> n >> m >> k;
 7     // max R = 12
 8     vector<vector<char>> grid(n + 1, vector<char>(m + 1));
 9     vector<vector<int>> P(n + 1, vector<int>(m + 1));
10     for (int i = 1; i <= n; i++) {
11         for (int j = 1; j <= m; j++) {
12             cin >> grid[i][j];
13         }
14     }
15     for (int i = 1; i <= k; i++) {
16         int x, y, p; 
17         cin >> x >> y >> p;
18         P[x][y] += p;
19     }
20     vector<i64> dp((1 << 13) + 50, -1E18);
21     dp[0] = 0;
22     for (int i = 1; i <= n; i++) {
23         for (int j = 1; j <= m; j++) {
24             if (P[i][j] == 0) continue;
25             vector<i64> dif(13);
26             i64 pw = 1;
27             for (int r = 1; r <= 12; r++) {
28                 pw *= 3;
29                 i64 dmg = 0;
30                 for (int x = 1; x <= n; x++) {
31                     for (int y = 1; y <= m; y++) {
32                         if (grid[x][y] == '#' && (i - x) * (i - x) + (j - y) * (j - y) <= r * r) {
33                             dmg += P[i][j];
34                         }
35                     }
36                 }
37                 dif[r] = dmg - pw;
38             }
39             for (int bit = (1 << 13); bit >= 0; bit--) {
40                 for (int x = 0; x < 13; x++) {
41                     if (bit >> x & 1) {
42                         dp[bit] = max(dp[bit], dp[bit ^ (1 << x)] + dif[x]);
43                     }
44                 }
45             }
46         }
47     }
48     // for (int i = 0; i < (1 << 13); i++) cout << dp[i] << ' ';
49     //     cout << '\n';
50     cout << *max_element(dp.begin(), dp.end()) << '\n';
51 }
52 int main() {
53     ios::sync_with_stdio(false);
54     cin.tie(nullptr); cout.tie(nullptr);
55 
56     int t; cin >> t;
57     while (t--) {
58         solve();
59     }
60 }
代码
复制代码

 

嗯,不错的题目。

 

posted on   yl_neo  阅读(54)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示