Educational Codeforces Round 181 (Rated for Div. 2) ABCD

Educational Codeforces Round 181 (Rated for Div. 2) ABCD

目录

ABCD 偏简单了

A

众所周知,竞赛可以用 \(s\) 字符串表示,该字符串由大写拉丁字母组成,表示问题。我们还知道,如果竞赛的连续子串中包含 "FFT "或 "NTT",那么竞赛就是有难度的。

你的任务是重新排列竞赛 \(s\) 中的问题,使其不难。如果最初的竞赛不难,您可以保持原样。

众所周知,一个竞赛可以用一个字符串 \(s\) 表示,这个字符串由表示问题的大写拉丁字母组成。我们还知道,如果竞赛中包含 "FFT "或 "NTT "这样的连续子串,那么这个竞赛就是有难度的。你的任务是重新排列竞赛 \(s\) 中的问题,使这个竞赛不难。如果最初的竞赛不难,您可以保持原样。


直接排序即可实现,不过我写烦了

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void sol()
{
    string s;
    cin >> s;
    int T = 0, N = 0, F = 0;
    for (char c : s)
    {
        if (c == 'T')
            T++;
        else if (c == 'N')
            N++;
        else if (c == 'F')
            F++;
        else
            cout << c;
    }
    while (T--)
        cout << 'T';
    while (N--)
        cout << 'N';
    while (F--)
        cout << 'F';
    cout << '\n';
}


B

在一个无限网格的 \((a,b)\) 单元中有一个机器人。米沙想要将它移动到 \((0,0)\) 单元。为此,他设定了一个整数 \(k\)

米沙可以执行以下操作:选择两个整数 \(dx\)\(dy\)$ (均从 \(0\)\(k\) 包括在内),然后将机器人向左移动 \(dx\) 个单元格(沿 \(x\) 坐标递减的方向),向下移动 \(dy\) 个单元格(沿 \(y\) 坐标递减的方向)。换句话说,将机器人从 \((x,y)\) 移动到 \((x - dx, y - dy)\)

操作成本为

  • \(1\) ,如果首次使用所选的 \((dx,dy)\) 对;
  • \(0\) ,如果之前已经选择过一对 \((dx,dy)\)

注意,如果是 \(dx \ne dy\) ,则 \((dx, dy)\)\((dy, dx)\) 会被视为不同的一对。

帮助米莎以最小的总成本将机器人带到 \((0,0)\) 小区。请注意,您不必尽量减少操作次数。


看到 请注意,您不必尽量减少操作次数。 就可以猜到答案要么是1,要么是2

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void sol()
{
    ll a, b, k;
    cin >> a >> b >> k;
    ll ans = 0;
    ll sm = __gcd(a, b);
    a /= sm;
    b /= sm;
    if (a <= k and b <= k)
        ans = 1;
    else
        ans = 2;
    cout << ans << '\n';
}

C

质数是正好有两个除数的正整数: \(1\) 和它本身。前几个质数是 \(2, 3, 5, 7, 11, \dots\)

正整数的质因数化就是将正整数表示为质数的乘积。例如

  • \(111\) 的质因数分解是 \(3 \cdot 37\)
  • \(43\) 的质因数分解是 \(43\)
  • \(12\) 的质因数分解是 \(2 \cdot 2 \cdot 3\)

对于每一个正整数,其质因数化都是唯一的(如果不考虑积中素数的顺序)。

如果一个正整数的因式分解中的****素数都至少包含两位数,我们就称它为。例如

  • \(343 = 7 \cdot 7 \cdot 7\) 不是好整数;
  • \(111 = 3 \cdot 37\) 不好;
  • \(1111 = 11 \cdot 101\) 好;
  • \(43 = 43\) 好。

您必须计算出从 \(l\)\(r\) 的好整数个数(包括端点)。(包括端点)。


容斥
可以暴力求

4
0 210
0 420
0 95
0 305

这组,然后观察发现可以分成长度为210的块算,剩余的暴力算。
[l,r]内的xx个数是经典的套路
可以转化成 前 N 个数的xx个数。

正解是容斥做,其实差不多


#include <bits/stdc++.h>
using namespace std;
using ll = long long;
ll f(ll x)
{
    ll block = x / 210;
    ll ans = block * 48;
    ll rem = x % 210;
    for (ll i = 1; i <= rem; ++i)
    {
        if (i % 2 == 0 || i % 3 == 0 || i % 5 == 0 || i % 7 == 0)
            continue;
        ++ans;
    }
    return ans;
}
void sol()
{
    // 2 3 5 7 -> 210
    ll l, r;
    cin >> l >> r;
    cout << f(r) - f(l - 1) << '\n';
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
 
    int t;
    cin >> t;
    while (t--)
    {
        sol();
    }
    return 0;
}


D

有一个线性条带,分为 \(m\) 个单元,从左到右编号为 \(1\)\(m\)

你会得到 \(n\) 个区段。每个区段由四个数字定义: \(l\)\(r\)\(p\)\(q\) --该区段包括从 \(l\)\(r\) 的单元格,并且存在的概率为 \(\frac{p}{q}\) (独立存在)。

您的任务是计算每个单元格仅被1个线段覆盖的概率。


第一眼想用图论做()
但是应该用DP做
本质上区别不大
赛后写了一个图论的,因为有点丑,所以以下代码经过gpt格式化。



#include <bits/stdc++.h>
using namespace std;
using namespace std;
 
const long long MOD = 998244353;
 
 
long long modexp(long long base, long long exp, long long mod = MOD)
{
    long long res = 1;
    base %= mod;
    while (exp > 0)
    {
        if (exp & 1)
            res = (res * base) % mod;
        base = (base * base) % mod;
        exp >>= 1;
    }
    return res;
}
 
long long modinv(long long x, long long mod = MOD)
{
    return modexp(x, mod - 2, mod);
}
 
struct Edge
{
    int u, v;
    long long weight;
};
 
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
 
    int n, m;
    cin >> n >> m;
 
    vector<vector<Edge>> graph(m + 1);
 
    long long globalFactor = 1;
 
    for (int i = 0; i < n; i++)
    {
        int l, r, pi, qi;
        cin >> l >> r >> pi >> qi;
        long long p = pi % MOD, q = qi % MOD;

        long long r_prob = (p * modinv(q)) % MOD; 
        long long one_minus = (1 - r_prob + MOD) % MOD;

        globalFactor = (globalFactor * one_minus) % MOD;
 
        long long weight = (r_prob * modinv(one_minus)) % MOD;
 
        Edge e;
        e.u = l - 1;
        e.v = r;
        e.weight = weight;
        graph[e.u].push_back(e);
    }
 
    vector<int> indegree(m + 1, 0);
    for (int u = 0; u <= m; u++)
    {
        for (auto &edge : graph[u])
        {
            indegree[edge.v]++;
        }
    }
 
    vector<long long> ways(m + 1, 0);
    ways[0] = 1;
 
    queue<int> q;
    for (int i = 0; i <= m; i++)
    {
        if (indegree[i] == 0)
            q.push(i);
    }
 
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        for (auto &edge : graph[u])
        {
            int v = edge.v;
            ways[v] = (ways[v] + ways[u] * edge.weight) % MOD;
 
            indegree[v]--;
            if (indegree[v] == 0)
                q.push(v);
        }
    }
 
    long long ans = (globalFactor * ways[m]) % MOD;
    cout << ans % MOD << "\n";
 
    return 0;
}

E(TODO)

如果整数集 \(Q\) 可以通过以下操作得到,我们就称它为互补和集:

  • 选择一个由 \(m\) 个正整数组成的数组 \(a\) ( \(m\) 是任意一个正整数);
  • 计算数组 \(a\) 中所有元素的和 \(s\)
  • 对于数组中的每个元素 \(a_{i}\) ,将数字 \(s - a_{i}\) 加到集合中,更正式的集合是
    \( Q = {s - a_{i}}; 1 \le i \le m \)

请注意, \(Q\) 不是一个多集合,也就是说其中的每个数字都是唯一的。例如,如果选择数组 \(a = [1, 3, 3, 7]\) ,那么 \(s = 14\)\(Q = \\{7, 11, 13\\}\)

你的任务是计算下列条件成立的互补和的不同集合的数目:

  • 集合恰好包含 \(n\) 个元素;
  • 集合中的每个元素都是一个从 \(1\)\(x\) 的整数。

如果第一个集合中有一个元素没有包含在第二个集合中,那么这两个集合就被认为是不同的。

由于答案可能很大,因此输出它取模 \(998,244,353\)


posted @ 2025-07-23 19:33  aminuosi  阅读(16)  评论(0)    收藏  举报