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\) 。
浙公网安备 33010602011771号