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;
}
posted @ 2025-10-13 17:31  williamYcY  阅读(27)  评论(0)    收藏  举报
/* */ /* */ /* */ /* */ /* */ /* */