Educational Codeforces Round 103 (Rated for Div. 2) 题解
A.K-divisible Sum
【题面】
给定 \(n\) 和 \(k\),构造一个有 \(n\) 个数的数组 \(a\),满足 \(a_1+a_2+...+a_n\) 可以被 k整除。要求 \(\max a_i\) 最小。
【思路】
1.考虑到如果让 \(a_1+a_2+...+a_n=xk\),令 \(x\) 为任意正整数,如果要让 \(\max a_i\) 最小,就考虑让所有 \(a_i\) 尽量平均。
2.所以可以让 \(a_1,a_2,...,a_{n-1}\) 等于 \(\lceil \frac{n}{k} \rceil\),然后让 \(a_n\) 也就是 \(\max a_i\) 变成最后的 \(xk - a_1 - a_2 - ... - a_{n-1}\)。
【实现】
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
inline int read(){
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9'){ x = x * 10 + (ch ^ 48); ch = getchar(); }
return x * f;
}
void solve(){
int n=read(), k=read();
int c = n/k;
if(n%k!=0){
c++;
}
int sum = k * c;
if(sum % n == 0)cout << sum/n << '\n';
else cout << sum/n + 1 << '\n';
}
int main(){
int T=read();
while(T--){
solve();
}
return 0;
}
B.Inflation
【题面】
给定一个 \(n\) 个数的数组 \(p_0,p_1,...,p_{n-1}\),\(p_i\) 表示第 \(i\) 个月的价格增长情况,其中 \(p_0\) 表示初始价格。
要使所有通货膨胀系数不超过 \(k\) %,您需要进行的最小更改总数是多少?
【思路】
1.可以发现主要的式子是 \(\frac{p_i}{p_0+p_1+...+p_{i-1}}\)
2.在不满足条件的情况下,显然需要减小分子或加大分母,但是无论是改动除 \(p_0\) 外的哪一个势必会牵扯到另一次所谓的“通货膨胀率”的计算(即改动了 \(p_i\),但是 \(p_i\)也会在其他计算中作为分母进行计算),所以显而易见只能改动 \(p_0\)。改动 \(p_0\) 方法较为简单,只需要二分最终的值即可。
【实现】
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
inline int read(){
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9'){ x = x * 10 + (ch ^ 48); ch = getchar(); }
return x * f;
}
void solve(){
ll n = read(), k = read();
vector<ll>p(n+1), sum(n+1, 0);
for(int i=1; i<=n; ++i) {
p[i] = read();
sum[i]=sum[i-1]+p[i];
}
ll Max=0;
for(int i=n; i>=2; --i) {
if(p[i]*100>sum[i-1]*k)
Max=max(Max,(p[i]*100-sum[i-1]*k+k-1)/k);
}
cout << Max << '\n';
}
int main(){
int T = read();
while(T--){
solve();
}
return 0;
}
C. Longest Simple Cycle
【题面】
给定 \(n\) 个长的为 \(c_i\) 的链
【思路】
考虑在每一条链上断掉。
前面有一些贡献。然后可以累加这一整条链。
每一次从两段跑到 \(a_{i+1},b_{i+1}\),如果这样累加都小于 \(b{i+1}−a_{i+1}\)。那直接重开即可。
【实现】
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
inline int read(){
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9'){ x = x * 10 + (ch ^ 48); ch = getchar(); }
return x * f;
}
int n;
int l[100010];
ll f[100010];
int a[100010], b[100010];
void solve(){
n = read();
for (int i = 1; i <= n; ++i) l[i] = read();
for (int i = 1; i <= n; ++i) a[i] = read();
for (int i = 1; i <= n; ++i) {
b[i]= read();
if (b[i] < a[i]) swap(a[i], b[i]);
}
a[1] = b[1] = 1;
f[1] = 0;
f[2] = b[2] - a[2] + 1;
ll ans = 0;
ans = max(ans, f[2] + l[2]);
for (int i = 3; i <= n; ++i) {
if (a[i] == b[i]) f[i] = 1;
else f[i] = max(f[i - 1] + abs(a[i] - 1) + abs(b[i] - l[i - 1]) + 2, 1ll * abs(a[i] - b[i]) + 1ll);\
ans = max(ans, f[i] + l[i]);
}
cout << ans << '\n';
}
int main(){
int T = read();
while(T--){
solve();
}
return 0;
}
D.Journey
【题面】
有 \(n + 1\) 个城市,编号从 \(0\) 到 \(n\) 。
每条路都有一个方向。方向由一串 \(n\) 字符给出,每个字符要么是L,要么是r。如果 \(i\) \的第一个字符是L,这意味着 \(i\) 的第一个路径最初是从城市 \(i\) 到城市 \(i - 1\) ;否则从城市 \(i - 1\) 到城市 \(i\) 。
一个旅行者希望尽可能多地游览这个国家的城市。最初,他们会选择一些城市开始他们的旅程。每天,旅行者必须从他们当前所在的城市前往邻近的城市,并且他们只能沿着与他们前进方向一致的道路行走;即。,如果一条道路从城市 \(i\) 指向城市 \(i + 1\) ,则可以从 \(i\) 行驶到 \(i + 1\) ,但不能从 \(i + 1\) 行驶到 \(i\) 。当旅行者搬到邻近的城市后,所有的道路都会改变方向。如果旅行者不能从当前的城市到邻近的城市,他们的旅程就结束了;旅行者也可以随时结束旅程。
旅行者的目标是尽可能多地访问不同的城市(他们可以多次访问一个城市,但只计算第一次访问)。对于每个城市 \(i\) ,计算旅行者在一次旅行中可以访问的不同城市的最大数量,如果他们从城市 \(i\) 出发。
【思路】
我们可以利用这些观察结果编写的解决方案之一是在 \(2n+2\) 顶点上构建一个无向图。每个顶点代表一对 \((v, k)\) ,其中 \(v\) 是我们目前所在的城市, \(k\) 是我们所做的移动次数,模 \(2\) 。由于每次移动都是到相邻的城市,因此从 \((v, 1)\) 无法到达每个顶点 \((v, 0)\) ,反之亦然。因为我们总是可以往回走,而且每一步都不会改变方向,所以这个图实际上是一个无向图。因此,我们可以使用DFS/BFS/DSU找到这个图的连通组件,并且对于每个城市 \(v\) ,打印出顶点 \((v, 0)\) 所属组件的大小。
【实现】
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
inline int read(){
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9'){ x = x * 10 + (ch ^ 48); ch = getchar(); }
return x * f;
}
const int maxn = 3e5 + 1;
ll t;
int l[maxn], r[maxn];
void solve(){
ll n;
n = read();
string s;
cin >> s;
s = " " + s;
l[0] = 0, l[1] = s[1] == 'L';
r[n] = 0, r[n - 1] = s[n] == 'R';
for (int i = 2; i <= n; i++) l[i] = s[i - 1] == 'R' && s[i] == 'L' ? l[i - 2] + 2 : s[i] == 'L';
for (int i = n - 2; i >= 0; i--) r[i] = s[i + 1] == 'R' && s[i + 2] == 'L' ? r[i + 2] + 2 : s[i + 1] == 'R';
for (int i = 0; i <= n; i++) cout << l[i] + r[i] + 1 << " "; cout << endl;
for (int i = 0; i <= n; i++) s[i] = l[i] = r[i] = 0;
}
int main(){
int T = read();
while(T--){
solve();
}
return 0;
}

浙公网安备 33010602011771号