首页 > 其他分享 >CF2034 A-E题解

CF2034 A-E题解

时间:2024-12-01 19:00:08浏览次数:8  
标签:s2 tx ty int 题解 s1 CF2034 ans

A. King Keykhosrow's Mystery

题意可以转化为存在 \(k_1,k_2\) 使得 \(m=a\times k_1+n = b\times k_2 +n\)。消去余数 \(n\) 得到 \(a\times k_1=b\times k_2\),即 \(a,b\) 的公倍数。所以最小的 \(m\) 就是 \(a,b\) 的最小公倍数,余数为 0。最小公倍数的计算方法是 \(\text{lcm}(a,b)=\dfrac{a\times b}{\gcd(a,b)}\)。

B. Rakhsh's Revival

考虑贪心的处理:逐位扫过去,维护一个变量 \(cnt\) 记录当前连续 \(0\) 的个数,遇到 \(1\) 就清空。因为提前操作并不能减少操作次数,所以我们仅当 \(cnt=m\) 时进行操作,把从这一位开始连续 \(k\) 个赋值成 \(1\)(实现时不用真的赋值,直接下标加 \(k\) 即可)。

int cnt = 0, ans = 0;
for (int i = 0; i < n; i++)
    if (s[i] == '1') { cnt = 0; continue; }
    else if (++cnt == m) i += k - 1, ans++, cnt = 0; // 因为for还要i++,这里只加k-1; 记得操作后cnt也要清零
cout << ans << '\n';

C. Trapped in the Witch's Labyrinth

对于 \(n\times m\) 个格子,可以分 4 种情况考虑:

  • 连通的一片 ?:把连通的一片 ? 拆分成一个个矩形。除了 \(1\times 1\) 的矩形,都可以每行构造成 >>>>>< ,一定走不出去;\(1\times 1\) 的矩形直接指向别的 ? 即可。
  • 孤立的一个 ?:它的周围没有别的 ? 了,当且仅当存在确定方向的格子指向它时,它走不出去(反向指对方即可)。注意多个格子指向它时也不成问题,只需要反指任意一个,别的格子都会被导向这个 >< 的循环里。
  • 方向确定,一定能走出去:根据固定的方向最终走到了边界,或者已经确定的“能走出去的格子”。它们对答案没有贡献,dfs 时顺带标记掉就好。
  • 方向确定,走不出去:最终指向了 ?,走不出去。

所以从每个格子出发 dfs,如果是 ? 则把连通块的大小计入答案(大小为 1 即孤立时先不计入,插入 set 中以备查询);如果确定了方向则判断是否会走出,把走不出的连通块大小加入答案。最后对于所有的孤立点检查上下左右有没有走不出去的,有的话答案加 \(1\)。

void solve(int test_case) {
    int n, m, siz, ans = 0;
    cin >> n >> m;
    vs s(n);
    vector<vc> vis(n, vc(m)); // 记录格子是否到达过
    vector<vc> out(n, vc(m)); // 记录格子是否会走出
    rep(i, 0, n - 1) cin >> s[i];
    set<pii> single; // 记录孤立点

    const int dx[4] = {-1, 1, 0, 0};
    const int dy[4] = {0, 0, -1, 1};
    map<char, int> mv = {{'U', 0}, {'D', 1}, {'L', 2}, {'R', 3}};

    auto inside = [&](int x, int y) -> bool {
        return x >= 0 && x < n && y >= 0 && y < m;
    };

    auto dfs1 = [&](auto&& dfs1, int x, int y) -> void { // 搜?的连通块
        vis[x][y] = 1;
        siz += 1;
        rep(i, 0, 3) {
            int tx = x + dx[i];
            int ty = y + dy[i];
            if (inside(tx, ty) && s[tx][ty] == '?' && !vis[tx][ty]) {
                dfs1(dfs1, tx, ty);
            }
        }
    };

    auto dfs2 = [&](auto&& dfs2, int x, int y) -> bool { // 搜方向确定的连通块
        vis[x][y] = 1;
        siz += 1;
        int d = mv[s[x][y]];
        int tx = x + dx[d];
        int ty = y + dy[d];
        if (!inside(tx, ty) || out[tx][ty]) {
            return out[x][y] = 1;
        }
        if (vis[tx][ty] || s[tx][ty] == '?') return 0;
        return out[x][y] = dfs2(dfs2, tx, ty);
    };

    rep(i, 0, n - 1) rep(j, 0, m - 1) {
        if (vis[i][j]) continue;
        siz = 0;
        if (s[i][j] == '?') {
            dfs1(dfs1, i, j);
            siz == 1 ? single.emplace(i, j), 0 : ans += siz;
        } else {
            ans += dfs2(dfs2, i, j) ? 0 : siz;
        }
    }
    for (auto [x, y] : single) {
        rep(i, 0, 3) {
            int tx = x + dx[i];
            int ty = y + dy[i];
            if (inside(tx, ty) && !out[tx][ty]) {
                ans += 1;
                break;
            }
        }
    }
    cout << ans << '\n';
}

D. Darius' Wisdom

用两个 set 记录 \(1,2\) 出现位置的下标,然后从后往前遍历,集合维护当前遍历位置前面的数(如果当前走到了 \(1,2\) 就从集合中删掉)。对于 \(0\) 来说,如果前面还有 \(2\),就从集合中找到一个 \(1\) 进行交换,再找到一个 \(2\) 进行交换;前面没有 \(2\) 了,就找到 \(1\) 进行交换;\(1\) 都没有则退出。对于 \(1\) 来说,如果前面有 \(2\) 就进行交换,否则跳过。次数显然小于 \(n\) 次。

void solve(int test_case) {
    int n;
    cin >> n;
    vi a(n);
    vector<pii> ans;
    set<int> s1, s2;
    rep(i, 0, n - 1) {
        cin >> a[i];
        if (a[i] == 1) {
            s1.insert(i);
        } else if (a[i] == 2) {
            s2.insert(i);
        }
    }
    dep(i, n - 1, 0) {
        if (a[i] == 2) {
            s2.erase(i); // 当前的2遍历过了,删掉
            continue;
        }
        if (a[i] == 1) {
            if (s2.empty()) {
                s1.erase(i); // 当前的1遍历过了,删掉
                continue;
            }
            int k = *s2.begin();
            s2.erase(k);
            swap(a[i], a[k]); // 交换1,2
            s1.erase(i);
            s1.insert(k); // 更新1的位置
            ans.emplace_back(i, k);
            continue;
        } // 下面 a[i] == 0
        if (s2.empty()) {
            if (s1.empty()) break; // 都没有,交换结束
            int k = *s1.begin();
            s1.erase(k); // 没有2了,1的位置就确定了,直接删掉
            swap(a[i], a[k]);
            ans.emplace_back(k, i);
        } else {
            int k1 = *s1.begin();
            int k2 = *s2.begin();
            s2.erase(k2); // 2的位置确定了,可以删掉
            s1.erase(k1);
            a[i] = 2, a[k1] = 0, a[k2] = 1;
            s1.insert(k2); // 更新1的位置
            ans.emplace_back(i, k1);
            ans.emplace_back(i, k2);
        }
    }
    cout << ans.size() << '\n';
    for (auto [i, j] : ans) {
        write("%d %d\n", i + 1, j + 1);
    }
}

E. Permutations Harmony

首先要判定一下 \(k\le n!\),这个只在 \(n\) 很小的情况下有可能超过,问题不大。然后注意到 \(k\) 为偶数时一定可以做,只需要找到 \(\dfrac{k}{2}\) 个对称的排列即可,如 1234|4321, 2134|3421 等。\(k\) 为奇数时,需要进一步讨论:

  • \(k=1\),只在 \(n=1\) 的情况下有解;\(k=n!-1\) 一定无解。
  • \(n\) 为偶数时一定无解,因为每个 \(i\) 的和相同,总和为 \(\dfrac{n(n+1)k}{2}\),每个 \(i\) 的和为 \(\dfrac{(n+1)k}{2}\),\(n\) 为偶数 \((n+1)k\) 除不开。
  • \(n\) 为奇数时,\(k\) 可以拆成 \(3\) 和 \(k-3\),后者为偶数,前者有贪心构造方案如图。

image

标签:s2,tx,ty,int,题解,s1,CF2034,ans
From: https://www.cnblogs.com/th19/p/18580164

相关文章

  • [CF603E] Pastoral Oddities 题解
    注意力惊人的注意到我们可以将问题转化为所有联通块大小全部为偶数。假如已经确认了所有加入的边,那么我们可以通过类似\(K\)算法的方式求解。考虑到答案单调不升,所以每条边都有一个影响的区间。考虑线段树分治。我们倒序枚举,遇到要加入的边,若当前时间为\(t\),边的加入时间为......
  • 【学校训练记录】12月个人训练赛1个人题解
    A对于n本书拿出k本较为难实现,但是从n本书里拿出n-k本就容易多了对于n本书里拿一本为特殊情况,不管怎么拿都为0对于n本书里拿n-k本的话,我们假设拿的最后一本为i那么他就是拿出n-k-1本书的情况再加上拿出第i本的情况其中差值变化为拿出n-k-1本书的值,加上我abs(w[i]-w[j])(j为拿......
  • odoo18运行报错问题解决
    File"/Users/melon/.pyenv/versions/3.11.9/lib/python3.11/code.py",line90,inruncodeexec(code,self.locals)File"<input>",line1,in<module>File"/Applications/PyCharm.app/Contents/plugins/python/helpers/p......
  • P11024 [COTS 2020] 定序 Redoslijed 题解
    先把是否有色的约束处理掉。累一个前缀和,对每个位置判一下即可。考察区间覆盖的性质,显然最后一个操作的区间内的颜色一定与其覆盖的颜色相同。考虑从后往前确定操作的顺序,一个操作只要满足这个条件就可以作为当前的最后一个操作,如果有多个满足条件的操作,随便取一个都合法。考虑......
  • 【题解】ABC382D Keep Distance
    题目描述你需要求出所有长度为\(n\),且满足以下条件的序列的个数,并按照字典序输出:首项大于等于\(1\),每一项比前一项至少大\(10\),最后一项小于等于\(m\)。题目分析爆搜,用vector存储答案和个数,输出。代码实现#include<iostream>#include<algorithm>#include<vector......
  • 洛谷P1880 [NOI1995] 石子合并 题解
    此题解以纪念我终于差不多大概搞懂区间dp了(插个存档点,到时候忘了再回来看看)。P1880[NOI1995]石子合并题解在做这道题之前,可以看看P1775石子合并(弱化版)(一道题解帮你搞定两道题,多划算)。P1775石子合并(弱化版)形式化的题面一堆石头摆在你面前,让你把他们扔到一起,每次扔......
  • 【Q1~Q6题解】第七届传智杯全国IT技能大赛-程序设计赛道第一场院校赛(初赛)思路+解题代
    本文为作者的题解解析。Q1~Q6,思路仅供参考文章目录Q1:汤姆和杰瑞解题代码解题思路Q2:游游的重组偶数解题代码解题思路Q3:小红的四子棋解题代码解题思路Q4:小欧的平面连线解题代码解题思路Q5:小红的数组操作解题代码解题思路Q6:游......
  • 国产化硬件系统上,部署视频监控平台系统软件出现的脚本问题解决
    目录一、问题描述二、解决方法        1、检查部署脚本权限        2、检查脚本中语法是否有问题        3、使用tee命令对文件进行修改        4、查看银河麒麟系统的安全设置        在国产系统银河麒麟硬件设备上部署视频......
  • P1135 奇怪的电梯 JAVA题解
    题目描述呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯。大楼的每一层楼都可以停电梯,而且第 ii 层楼(1≤i≤N1≤i≤N)上有一个数字 KiKi​(0≤Ki≤N0≤Ki​≤N)。电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果不能满足要求,相应的按钮就会失灵。例......
  • P2658 汽车拉力比赛 JAVA题解
    package篮桥杯.d;importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.StreamTokenizer;importjava.util.LinkedList;importjava.util.Queue;publicclassMain{//自定义的输入类,比普通Scanner快两......