Codeforces Round 921 (Div. 2)
Codeforces Round 921 (Div. 2)
推荐题解
A - We Got Everything Covered!
解题思路:
以前\(k\)个字符都出现过至少一次为一轮,构造\(n\)轮即可。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
void solve()
{
int n, k;
cin >> n >> k;
string s;
for (int i = 0; i < k; i++)
{
char c = 'a' + i;
s += c;
}
string t = s;
for (int i = 2; i <= n; i++)
{
s += t;
}
cout << s << endl;
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
B - A Balanced Problemset?
解题思路:
假设我们结果的最大公因数为\(g\),那么分出的\(n\)个数字分别为\((k_1g,k_2g,...,k_ng)\)。所以\(x = \sum\limits_{i = 1}^nk_ig\)。
所以\(g\)一定是\(x\)的因子。
筛出所有因子,遍历,能分出\(n\)份即可,取最大。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
void solve()
{
ll x, n;
cin >> x >> n;
vector<ll> v;
for (int i = 2; i <= x / i; i++)
{
if (x % i == 0)
{
v.push_back(i);
if (x / i != i)
{
v.push_back(x / i);
}
}
}
v.push_back(1);
v.push_back(x);
ll ans = 0;
for (auto a : v)
{
ll k = x / a;
// cout << a << ' ' << k << endl;
if (k >= n)
{
ans = max(ans, a);
}
}
cout << ans << endl;
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
C - Did We Get Everything Covered?
解题思路:
合法要求同第一题:以前\(k\)个字符都出现过至少一次为一轮,构造\(n\)轮即可.
判断是否有\(n\)轮,如果不满足,即只有\(s\)轮,\(s < n\)。
我们先取前\(k\)轮中每轮的最后一个字符。
然后选取一个第\(k + 1\)轮缺少的字符,一直加到字符长度为\(n\),该字符一定不是给定字符的子串。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
void solve()
{
int n, k, m;
cin >> n >> k >> m;
string s;
cin >> s;
int cur = 0;
int cnt = 0;
vector<bool> vis(26);
string ans;
for (auto c : s)
{
int x = c - 'a';
if (x < k && !vis[x])
{
vis[x] = true;
cnt++;
if (cnt == k)
{
ans += c;
for (int i = 0; i < 26; i++)
{
vis[i] = false;
}
cnt = 0;
cur++;
}
}
}
if (cur < n)
{
puts("NO");
char c;
for (int i = 0; i < k; i++)
{
if (!vis[i])
{
c = i + 'a';
}
}
while (ans.size() < n)
{
ans += c;
}
cout << ans << endl;
}
else
{
puts("YES");
}
}
int main()
{
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
D - Good Trip
解题思路:
首先,我们每次出行要从\(n\)个人中选取两个人,即\(C(n,2) = \binom{n}{2} = \frac{n *(n -1)}{2}\)。
那么,每次选择到我们固定要的一对二人组的概率就是\(p = \frac{1}{\binom{n}{2}}\),选不到我们要的二人组的概率为\(q = 1 - p\)。
我们有\(k\)次出行,那么\(k\)个二人组中共选到某一个特定二人组\(i\)次的概率为\(\binom{k}{i} \times p^{i}\times q^{k -i}\)。
如果这个特定二人组不是朋友,那么他们的期望为\(0 \times \binom{k}{i} \times p^{i}\times q^{k -i} = 0\)
如果这个特定二人组不是朋友,且初始友谊值为\(f_a\), 那么他们的期望为\(\sum\limits_{j = 0}^{i - 1}(f_a+j) \times \binom{k}{i} \times p^{i}\times q^{k -i}\)。即每选到一次后,友谊值都会加\(1\).
我们要求的是所有情况的期望,也就是每个情况的期望的和。
由上可知,不是朋友的二人组期望贡献为\(0\),所以我们只需要将朋友二人组的期望加起来即可。
有\(m\)组朋友二人组,将他们累加:
设\(s = \sum\limits_{a =1}^m f_a\)化简:
明显,等差数列高斯求和。
遍历\(0 \sim k\),对上式求各种情况和即为答案。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
int n, m, k;
ll f[N];
ll inv[N];
ll qmi(ll a, ll b)
{
ll res = 1;
while (b)
{
if (b & 1)
{
res = res * a % mod;
}
b >>= 1;
a = a * a % mod;
}
return res;
}
ll C(ll a, ll b)
{
if (a == b || b == 0)
{
return 1;
}
return (f[a] * inv[a - b] % mod) * inv[b] % mod;
}
ll S(ll l, ll cnt)
{
return ((l + (l + (cnt - 1) * m)) * cnt % mod) * inv[2] % mod;
}
void init(int n)
{
f[0] = 1;
for (int i = 1; i <= n; i++)
{
f[i] = f[i - 1] * i % mod;
}
inv[n] = qmi(f[n], mod - 2);
for (int i = n - 1; i; i--)
{
inv[i] = (i + 1) * inv[i + 1] % mod;
}
}
void solve()
{
cin >> n >> m >> k;
ll sum = 0;
for (int i = 1; i <= m; i++)
{
int a, b, c;
cin >> a >> b >> c;
sum = (sum + c) % mod;
}
ll ans = 0;
ll p = qmi(C(n, 2), mod - 2) % mod;
ll q = (((1 - p) % mod) + mod) % mod;
// cout << C(n, 0) << endl;
for (int i = 0; i <= k; i++)
{
// cout << i << ' ' << S(sum, i) << ' ' << C(k, i) * qmi(p, i) << ' ' << ' ' << endl;
ans = (ans + ((S(sum, i) * (C(k, i) * qmi(p, i) % mod) % mod) * qmi(q, k - i) % mod)) % mod;
}
cout << ans << endl;
}
int main()
{
int t = 1;
init(2e5 + 5);
cin >> t;
while (t--)
{
solve();
}
return 0;
}
E - Space Harbour
原本想看了思路就重构代码,但被卡吐了,于是就对着代码重构了。。。
建议观看视频加自己画图理解。
解题思路:
我们将两个港口之间的船只消费之和记录到他们的右侧港口上。
设区间船只到右侧港口距离之和为\(sum\),左侧港口价值为\(val\),那么右侧港口记录值为\(sum \times val\)
假设我们插入港口位置为\(x\),他左边最近的港口为\(l\),右侧最近的港口为\(r\)。那么对于\(r\)所记录的值\(sum \times val\),我们重新计算\((x,r)\)之间船只的花费然后记录即可。对于\(l\)港口无需处理。对于港口\(x\),我们记录\((l,x)\)之间船只的花费。
对于查询,假设我们有港口\((1,4,6,9,12)\)。
我们查询区间\((5,10)\)。
我们先求得港口\((6,9,12)\)上花费累加的和,该和为\(4\sim 12\)的花费。然后我们再减去\(4\sim 5,11\sim 12\)的花费即可得到答案。
上述操作中,修改港口花费为单点修改,查询区间和为区间查询。用线段树处理\(O(logn)\)
无论是更新花费还是计算需减去的花费复杂度都是\(O(1)\)。
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<ll, ll>;
#define fi first
#define se second
using i128 = __int128_t;
const int N = 3e5 + 10;
int n, m, q;
ll w[N];
ll sum[N];
ll t[N * 4];
void pushup(int u)
{
t[u] = t[u << 1] + t[u << 1 | 1];
}
void update(int u, int l, int r, int idx, ll val)
{
if (l == r && r == idx)
{
t[u] = val;
return;
}
int mid = l + r >> 1;
if (idx <= mid)
{
update(u << 1, l, mid, idx, val);
}
else
{
update(u << 1 | 1, mid + 1, r, idx, val);
}
pushup(u);
}
void change(ll l, ll r, ll val)
{
ll len = r - l - 1;
w[r] = val;
sum[r] = val * (1 + len) * len / 2;
update(1, 1, n, r, sum[r]);
}
ll query(int u, int l, int r, int nl, int nr)
{
if (l >= nl && r <= nr)
{
return t[u];
}
int mid = l + r >> 1;
ll res = 0;
if (nl <= mid)
{
res += query(u << 1, l, mid, nl, nr);
}
if (nr > mid)
{
res += query(u << 1 | 1, mid + 1, r, nl, nr);
}
return res;
}
void solve()
{
cin >> n >> m >> q;
vector<int> v(m + 1);
for (int i = 1; i <= m; i++)
{
cin >> v[i];
}
for (int i = 1; i <= m; i++)
{
int x;
cin >> x;
w[v[i]] = x;
}
set<ll> s;
sort(v.begin() + 1, v.end());
s.insert(v[1]);
s.insert(v[m]);
change(1, n, w[v[1]]);
for (int i = m - 1; i >= 2; i--)
{
s.insert(v[i]);
change(v[i], v[i + 1], w[v[i]]);
change(v[1], v[i], w[v[1]]);
}
while (q--)
{
int op;
cin >> op;
if (op == 1)
{
ll x, v;
cin >> x >> v;
ll l = *prev(s.lower_bound(x));
auto r = *s.lower_bound(x);
s.insert(x);
change(l, x, w[r]);
change(x, r, v);
}
else
{
ll l, r;
cin >> l >> r;
auto nl = *s.lower_bound(l);
auto nr = *s.lower_bound(r);
ll ans = query(1, 1, n, nl, nr);
ll res = 0;
ll len = 0;
len = nr - r - 1;
res += w[nr] * (1 + len) * len / 2;
len = nl - l;
res += sum[nl] - w[nl] * (1 + len) * len / 2;
cout << ans - res << "\n";
}
}
}
int main()
{
int t = 1;
// cin >> t;
while (t--)
{
solve();
}
return 0;
}

浙公网安备 33010602011771号