2025.7.16

刷题日记

第一次单切1700,还是一遍过,太爽了


Codeforces Round 1034 (Div. 3) F. Minimize Fixed Points
https://codeforces.com/contest/2123/problem/F
要求构造一个排列p,使得 gcd(p[i], i) != 1 的数量最大化
简单地说,就是每一位的p[i]和i,尽可能让他们不互质就行
那么怎么样可以不互质呢?


我们可以很快的想到一种思路,就是让所有2的倍数错位填充,所有3的倍数错位填充,这样就可以解决了
至于在n的范围内实在找不到倍数的,那就填他自己,毕竟题目要求是“最大化”而非“全都是”
但是依据这个思路,衍生出一个问题:
对于数字“6”这样的既是2的倍数又是3的倍数的数字,该当作2的倍数还是3的倍数呢
为了解决这个问题,我们可以倒着想,在一定的范围内,2的倍数显然比3的倍数多
那也就是说,3的条件相对难满足,2的条件相对容易满足,因此我们就应该优先考虑3的情况
但还有一种情况,8既是2的倍数又是4的倍数,这种情况下该填谁?
显然我们知道,4也是2的倍数,所以对于已经是合数的数字,我们不再去考虑他的倍数


那么我们最终的解决方案已经出来了,就是对于给定的数字n,去从大到小遍历n以内的所有质数
并将他们的倍数全部存起来,存过的标记为1,后续遍历到小的质数时不再被使用
我们可以用线性筛预处理所有的质数,代码如下:

点击查看代码
#include <bits/stdc++.h>
#include <bits/extc++.h>

#define debug(x) std::cout << #x << " = " << x << '\n'
#define debugp(x, y) std::cout << #x << ", " << #y << " = " << "[" << x << ", " << y << "]\n"
#define debugt(x, y, z) std::cout << #x << ", " << #y << ", " << #z << " = " << "[" << x << ", " << y << ", " << z << "]\n"
#define debug1(f, a, b) std::cout << #f << ": "; for (int i = (a); i <= (b); i++) std::cout << (f)[i] << " \n"[i == (b)]
#define debug2(f, a, b, c, d) std::cout << #f << ":\n"; for (int i = (a); i <= (b); i++) for (int j = (c); j <= (d); j++) std::cout << (f)[i][j] << " \n"[j == (d)]
#define debug_1(q) std::cout << #q << ": ";  for (auto it : (q)) std::cout << it << ' '; std::cout << '\n'
#define debug_2(q) std::cout << #q << ":\n"; for (auto [x, y] : (q)) std::cout << '[' << x << ", " << y << "]\n"
#define debug_3(q) std::cout << #q << ":\n"; for (auto [x, y, z] : (q)) std::cout << '[' << x << ", " << y << ", " << z << "]\n"  
#define show(q) std::cout << #q << ": "; while ((q).size()) { std::cout << (q).top() << ' '; (q).pop(); } std::cout << '\n';

using i64 = long long;
using namespace __gnu_pbds;
using ordered_set = tree<i64, null_type, std::less<i64>, rb_tree_tag, tree_order_statistics_node_update>;
using ordered_multiset = tree<i64, null_type, std::less_equal<i64>, rb_tree_tag, tree_order_statistics_node_update>;

constexpr int N = 1e5 + 10;
constexpr int inf = INT_MAX;
constexpr i64 INF = LLONG_MAX;
constexpr int mod = 998244353;

//====================Solution-bg====================//

std::vector<int> prim(N);
int now;
bool vis[N];

void init () {
    for (int i = 2; i <= N; i++) {
        if (!vis[i]) {
            prim[++now] = i;
            vis[i] = 1;
        }

        for (int j = 1; j <= now && prim[j] * i <= N; j++) {
            vis[prim[j] * i] = 1;
            if (i % prim[j] == 0) break;
        }
    }
}

void solve () {
    int n;
    std::cin >> n;

    std::vector<int> st[n + 1];
    std::vector<int> Vis(n + 1, 0);
    std::vector<int> ans(n + 1);

    int id = 1;
    while (prim[id] < n) id++;
    id--;

    for (int i = id; i >= 1; i--) {
        for (int j = 2; prim[i] * j <= n; j++) {
            if (Vis[prim[i] * j]) continue;
            st[prim[i]].push_back(prim[i] * j);
            Vis[prim[i] * j] = 1;
        }
    }

    for (int i = 1; i <= n; i++) {
        int len = st[i].size();

        if (len) {
            ans[i] = st[i][0];
            for (int j = 0; j < len - 1; j++) {
                ans[st[i][j]] = st[i][j + 1];
            }
            ans[st[i][len - 1]] = i;
        }
    }

    for (int i = 1; i <= n; i++) {
        if (!ans[i]) {
            ans[i] = i;
        }
        std::cout << ans[i] << " \n"[i == n]; 
    }
}

//====================Solution-ed====================//

int32_t main () {   
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    init();

    int t = 1;
    std::cin >> t;

    while (t--) {
        solve();
    }
    
    return 0;
}


Codeforces Round 1031 (Div. 2) C. Smilo and Minecraft
https://codeforces.com/contest/2113/problem/C
给定一个二维矩阵,其中一部分是金矿,一部分是石头,剩下的都是空格
给你TNT的爆炸半径,爆炸半径以内的全部摧毁,半径向外延申一格围成的这一圈全部收集,问你最多能收集到多少金矿


这道题真是纯纯的思维题,以为是dp那种的推了好久推不出来,毫无头绪
我们可以看到,当你第一次炸完之后,
只需要沿着第一次爆炸后,所产生的空间的最外面这一圈,依次去爆破,就一定能收集到剩下的所有金矿!
所以问题就转化为,如何去最小化第一次产生的损失


而每次爆炸的损失,其实就是计算子矩阵的和,但是如果我们暴力计算,肯定TLE
所以我们需要使用二维前缀和,然后双层for循环遍历每一个点,找到第一次爆炸损失最小的部分
然后让 (金矿总数 - 第一次爆炸的最小损失) 就是最终答案,代码如下

点击查看代码
#include <bits/stdc++.h>
#include <bits/extc++.h>

#define debug(x) std::cout << #x << " = " << x << '\n'
#define debugp(x, y) std::cout << #x << ", " << #y << " = " << "[" << x << ", " << y << "]\n"
#define debugt(x, y, z) std::cout << #x << ", " << #y << ", " << #z << " = " << "[" << x << ", " << y << ", " << z << "]\n"
#define debug1(f, a, b) std::cout << #f << ": "; for (int i = (a); i <= (b); i++) std::cout << (f)[i] << " \n"[i == (b)]
#define debug2(f, a, b, c, d) std::cout << #f << ":\n"; for (int i = (a); i <= (b); i++) for (int j = (c); j <= (d); j++) std::cout << (f)[i][j] << " \n"[j == (d)]
#define debug_1(q) std::cout << #q << ": ";  for (auto it : (q)) std::cout << it << ' '; std::cout << '\n'
#define debug_2(q) std::cout << #q << ":\n"; for (auto [x, y] : (q)) std::cout << '[' << x << ", " << y << "]\n"
#define debug_3(q) std::cout << #q << ":\n"; for (auto [x, y, z] : (q)) std::cout << '[' << x << ", " << y << ", " << z << "]\n"  
#define show(q) std::cout << #q << ": "; while ((q).size()) { std::cout << (q).top() << ' '; (q).pop(); } std::cout << '\n';

using i64 = long long;
using namespace __gnu_pbds;
using ordered_set = tree<i64, null_type, std::less<i64>, rb_tree_tag, tree_order_statistics_node_update>;
using ordered_multiset = tree<i64, null_type, std::less_equal<i64>, rb_tree_tag, tree_order_statistics_node_update>;

constexpr int N = 2e5 + 10;
constexpr int inf = INT_MAX;
constexpr i64 INF = LLONG_MAX;
constexpr int mod = 998244353;

//====================Solution-bg====================//

void solve () {
    int n, m, k;
    std::cin >> n >> m >> k;

    std::vector map(n + 1, std::vector<char>(m + 1));
    std::vector sum(n + 1, std::vector<int>(m + 1));
    int all = 0, lose = inf;

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            std::cin >> map[i][j];
            if (map[i][j] == 'g') all++;
        }
    }

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + (map[i][j] == 'g');
        }
    }

    auto ask = [&] (int x, int y) {
        int x1, y1, x2, y2;
        x1 = std::max(0, x - k);
        y1 = std::max(0, y - k);
        x2 = std::min(n, x + k - 1);
        y2 = std::min(m, y + k - 1);

        return sum[x2][y2] - sum[x1][y2] - sum[x2][y1] + sum[x1][y1];
    };

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (map[i][j] == '.') {
                lose = std::min(ask(i, j), lose);
            }
        }
    }
    std::cout << all - lose << '\n';
}

//====================Solution-ed====================//

int32_t main () {   
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int t = 1;
    std::cin >> t;

    while (t--) {
        solve();
    }
    
    return 0;
}
posted @ 2025-07-16 11:20  _彩云归  阅读(71)  评论(0)    收藏  举报