[CF1902] Educational Codeforces Round 159 A~E 题解
[CF1902] Educational Codeforces Round 159 A~E 题解
A. Binary Imbalance
很快观察到如果有不同的相邻元素,那么一定有解,意味着如果全是 1 无解,其他有解
B. Getting Points
题面很长,可以发现,最好的偷懒方式一定是把所有的课都拖到最后几天上(真实),可以简单调整证明这样是不劣的,最后几天上的课有三种课:
- 完成两个任务
- 完成一个任务
- 不做任务
推推式子就出了。
void work() {
int n, p, a, b;
cin >> n >> p >> a >> b;
int t = (n - 1) / 7 + 1;
int cnt = t / 2;
int ans = 0;
if(cnt * (a + 2 * b) >= p) {
cout << n - ((p + a + 2 * b - 1) / (a + 2 * b)) << '\n';
return ;
}
p -= cnt * (a + 2 * b);
ans += cnt;
if((t % 2 == 1) && a + b >= p) {
cout << n - 1 - cnt << '\n';
return ;
}
else if((t % 2 == 1)) {
ans ++;
p -= a + b;
}
cout << n - ans - ((p + a - 1) / a) << '\n';
return ;
}
C. Insert and Equalize
考虑如果不加入新元素是什么情况。
那么最后一定会等于最大数,否则可以同时减去
那么这个
考虑加入新元素,那么显然不应该使
此时 。 ,此时 , 是使得 不重复的最小的正整数。
取
void work() {
cin >> n;
s.clear();
for(int i = 1; i <= n; i ++) cin >> a[i], s.insert(a[i]);
if(n == 1) { // 要读完 a1 再return 不然会吃两发罚时
cout << 1 << '\n';
return ;
}
sort(a + 1, a + n + 1);
int ans = 0, d = a[2] - a[1];
for(int i = 3; i <= n; i ++) {
d = gcd(d, a[i] - a[i - 1]);
}
for(int i = 1; i <= n; i ++)
ans += (a[n] - a[i]) / d;
int pos = 1e9;
for(int i = 1; i <= n + 1; i ++)
if(s.find(a[n] - i * d) == s.end()) {
pos = i;
break;
}
cout << ans + min(n, pos) << '\n';
return ;
}
D. Robot Queries
先模拟处理出
观察到反转操作实际上是把所有原路径上的点关于
所以我们现在需要维护在
观察到值域比较小,可以使用 vector
维护每一个点在哪些时刻被经过,查询的时候二分
vector<int> c[N];
bool calc(int l, int r, int t) {
int lp = lower_bound(c[t].begin(), c[t].end(), l) - c[t].begin(), rp = upper_bound(c[t].begin(), c[t].end(), r) - c[t].begin() - 1;
return lp <= rp;
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> q >> s;
c[id({0, 0})].push_back(0);
for(int i = 0, x = 0, y = 0; i < n; i ++) {
if(s[i] == 'U') y ++;
if(s[i] == 'D') y --;
if(s[i] == 'L') x --;
if(s[i] == 'R') x ++;
p[i + 1] = {x, y};
c[id({x, y})].push_back(i + 1);
}
for(int i = 1, x, y, l, r; i <= q; i ++) {
cin >> x >> y >> l >> r;
if(calc(0, l - 1, id({x, y})) || calc(r, n, id({x, y})) || calc(l, r - 1, id({p[l - 1].x + p[r].x - x, p[l - 1].y + p[r].y - y})))
cout << "YES\n";
else
cout << "NO\n";
}
return 0;
}
E. Collapsing Strings
首先正难则反方便做,用总字符串长度减去被消掉的长度,观察到
看到前缀考虑 Trie,插入所有字符串的反转,在插入的路径上增加 1 的贡献,意味着多匹配了一个字符,之后枚举
最后需要
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
// #define int long long
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
typedef long long ll;
const int N = 1e6 + 10, M = 2e6 + 10;
int tr[M][26], cnt[M], idx;
void update(string s) {
int u = 0;
for(int i = (int)s.size() - 1; i >= 0; i --) {
int c = s[i] - 'a';
if(!tr[u][c]) tr[u][c] = ++ idx;
u = tr[u][c];
cnt[u] ++;
}
}
int query(string s) {
int u = 0, ans = 0;
for(int i = 0; i < s.size(); i ++) {
int c = s[i] - 'a';
if(tr[u][c]) u = tr[u][c];
else break;
ans += cnt[u];
}
return ans;
}
int n;
string s[N];
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i ++) cin >> s[i], update(s[i]);
long long ans = 0;
for(int i = 1; i <= n; i ++) ans += s[i].size();
ans = ans * 2 * n;
for(int i = 1; i <= n; i ++)
ans -= 2 * query(s[i]);
cout << ans << '\n';
return 0;
}
总结
B 一开始没看懂题,切慢了一点,不过亮点是把所有情况都讨论了一发过,C 交了两发罚时,以后注意一下特判的时候要保证所有的数据都读完了。
E 莽对了一发过,但是 D 观察到中点对称的性质之后没有想到怎么维护,看了
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现