Codeforces Round #621 (Div. 1 + Div. 2)
【A.Cow and Haybales】
【题目大意】
有一个长为n的序列,每次你可以选择一个位置使其减去1并使其其中一个相邻的位置加上1,问你d次内序列首项的最大值是多少
【解题思路】
显然将posi上的数移动一个到首项上所花的次数为posi,贪心能移就移,那么O(n)模拟就好了
【AC代码】
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) {
int n, d, day = 0, sum = 0;
cin >> n >> d >> sum;
for (int i = 1; i < n; ++i) {
int x;
cin >> x;
int add = x * i;
if (day + add <= d) {
sum += x;
day += add;
}
else {
sum += (d - day) / i;
day = d;
}
}
cout << sum << endl;
}
return 0;
}
【B.Cow and Friend】
【题目大意】
从(0, 0)出发,每次你可以跳跃一次到距离该位置ak的位置,问最少跳跃几次到达(x, 0)
【解题思路】
有两种跳法,如果是直线跳跃,那么跳跃一次到x轴上,否则斜着跳,可以考虑三角形两边之和大于第三边,如果x大于a序列中的最大值的两倍,那么先跳直线,直到距离小于等于最大值的两倍,否则可能可以跳跃1次到达x或者跳跃2次到达x
【AC代码】
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) {
int n, x;
cin >> n >> x;
int Max = 0;
bool flag = false;
for (int i = 1; i <= n; ++i) {
int y;
cin >> y;
if (x == y) {
flag = true;
}
Max = max(Max, y);
}
if (flag) {
cout << 1 << endl;
continue;
}
if (x % Max == 0) {
cout << max(x / Max, 1) << endl;
continue;
}
int ans = x / Max + 1;
cout << max(ans, 2) << endl;
}
return 0;
}
【C.Cow and Message】
【题目大意】
给定一个字符串,问你其子序列中出现次数最多的次数
【解题思路】
考虑出现次数最多的子序列长度不会大于2,假设其长度为3,如abc,那么num(ab) >= num(abc),那么dp[i][j]表示每一位字符i的上一位为j出现的次数,cnt[j]表示该位之前字符j出现的次数,那么dp[i][j] = dp[i][j] + cnt[j]
ans = max(ans, dp[i][j], cnt[j])
【AC代码】
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
ll dp[26][26];
ll cnt[26];
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
string s;
cin >> s;
int l = s.length();
for (int i = 0; i < l; ++i) {
int ch = s[i] - 'a';
for (int j = 0; j < 26; ++j) {
dp[ch][j] += cnt[j];
}
++cnt[ch];
}
ll ans = 0;
for (int i = 0; i < 26; ++i) {
for (int j = 0; j < 26; ++j) {
ans = max(ans, dp[i][j]);
}
}
for (int i = 0; i < 26; ++i) ans = max(ans, cnt[i]);
cout << ans << endl;
return 0;
}
【D.Cow and Fields】
【题目大意】
给定一个无向图,你需要在k个节点中选择两个点连上一条边,问你最短路的最大值是多少
【解题思路】
假设你选择x和y连上一条边,那么该路径长度为min(dis1[x] + 1 + disn[y], dis1[y] + 1 + disn[x]),假设dis1[x] + 1 + disn[y] < dis1[y] + 1 + disn[x],移项得到dis1[x] - disn[x] < dis1[y] - disn[y],根据这个式子对k个节点排序就可以保证路径上不会经过重复节点,然后我们可以枚举y = a[i],ans = max(ans, tmp + 1 + disn[a[i]]),其中tmp为i之前距离1的最大值
dis数组可以通过bfs得到
【AC代码】
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
const int maxn = 2e5 + 10;
int a[maxn];
int dis1[maxn];
int disn[maxn];
bool vis[maxn];
vector<int> G[maxn];
inline bool cmp(int x, int y) {
return dis1[x] - disn[x] < dis1[y] - disn[y];
}
inline void bfs(int s, int dis[]) {
queue<int> que;
que.push(s);
dis[s] = 0;
memset(vis, false, sizeof(vis));
vis[s] = true;
while (!que.empty()) {
int u = que.front();
que.pop();
for (auto v : G[u]) {
if (!vis[v]) {
dis[v] = dis[u] + 1;
que.push(v);
vis[v] = true;
}
}
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, m, k;
cin >> n >> m >> k;
for (int i = 1; i <= k; ++i) cin >> a[i];
for (int i = 1; i <= m; ++i) {
int u, v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
bfs(1, dis1);
bfs(n, disn);
sort(a + 1, a + k + 1, cmp);
int ans = 0, tmp = dis1[a[1]];
for (int i = 2; i <= k; ++i) {
ans = max(ans, tmp + 1 + disn[a[i]]);
tmp = max(tmp, dis1[a[i]]);
}
cout << min(ans, dis1[n]) << endl;
return 0;
}