[CF1902] Educational Codeforces Round 159 A~E 题解

[CF1902] Educational Codeforces Round 159 A~E 题解

A. Binary Imbalance

很快观察到如果有不同的相邻元素,那么一定有解,意味着如果全是 1 无解,其他有解

B. Getting Points

题面很长,可以发现,最好的偷懒方式一定是把所有的课都拖到最后几天上(真实),可以简单调整证明这样是不劣的,最后几天上的课有三种课:

  1. 完成两个任务
  2. 完成一个任务
  3. 不做任务

推推式子就出了。

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

考虑如果不加入新元素是什么情况。

那么最后一定会等于最大数,否则可以同时减去 x 这样更优。

那么这个 x 就必须整除所有元素和最大数的差,取个 gcd 即可。

考虑加入新元素,那么显然不应该使 x 变小,所以只有两种情况。

  1. an+1>an 此时 an+1=an+x
  2. an+1<an,此时 an+1=ankxk 是使得 an+1 不重复的最小的正整数。

min 即可。

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

先模拟处理出 pi 表示第 i 次执行后机器人坐标。

观察到反转操作实际上是把所有原路径上的点关于 pl,pr 的中点做对称,不妨把查询的 (x,y) 关于中点做对称再直接查询原路径上的点,由对称性,这样是等价的。

所以我们现在需要维护在 [l,r] 时刻,(x,y) 是否被经过。

观察到值域比较小,可以使用 vector 维护每一个点在哪些时刻被经过,查询的时候二分 l,r 即可。

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

首先正难则反方便做,用总字符串长度减去被消掉的长度,观察到 C(a,b) 函数的本质是求 LCP(reva,b)reva 表示 a 的反转。

看到前缀考虑 Trie,插入所有字符串的反转,在插入的路径上增加 1 的贡献,意味着多匹配了一个字符,之后枚举 b,在 Trie 上跑匹配,统计路径上所有的贡献。

最后需要 ×2,因为这样只会统计 b 作为第二个字符串的贡献。

#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 观察到中点对称的性质之后没有想到怎么维护,看了 \color{black}g\color{red}yh20 大佬的代码之后恍然大悟。

posted @   MoyouSayuki  阅读(59)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
:name :name
点击右上角即可分享
微信分享提示