AtCoder Beginner Contest 370 Solution

A

void solve() {
    int a, b;
    qr(a, b);
    if(a + b != 1) cout << "Invalid\n";
    else Yes(a);
}

B

模拟

void solve() {
    qr(n);
    int x = 1;
    FOR(i, n) FOR(j, i) qr(a[i][j]);
    FOR(i, n) x = x >= i ? a[x][i]: a[i][x];
    pr2(x);
}

C

首先先考虑能变小的位置, 此时选择更前面的位置对字典序的改变更优. 反之, 先选后面的位置更优.

void solve() {
    string s, t;
    qr(s, t);
    n = SZ(s);
    VT<int> v[2];
    m = 0;
    rep(i, 0, n - 1) 
        if(s[i] != t[i])
            v[s[i] < t[i]].pb(i);
    pr2(SZ(v[0]) + SZ(v[1]));
    reverse(v[1]);
    rep(i, 0, 1) {
        for(int j: v[i]) s[j] = t[j], pr2(s);
    }
}

D

维护 n + m n+m n+m 个set,用内置函数查找. 需要注意的时,先删除 prev(it), 再删除 it. 否则迭代器可能异常.

void solve() {
    qr(n, m, q);
    VT r(n + 1, set<int>()), c(m + 1, set<int>());
    FOR(i, n) FOR(j, m) r[i].insert(j), c[j].insert(i);
    int x, y;
    auto del = [&](int x, int y) {
        r[x].erase(y); 
        c[y].erase(x);
    };
    while(q--) {
        qr(x, y);
        if(r[x].contains(y)) {
            del(x, y);
            continue;
        }
        if(SZ(c[y])) {
            auto jt = c[y].upper_bound(x);
            if(jt != c[y].begin()) del(*prev(jt), y);
            if(jt != c[y].end()) del(*jt, y);
        }
        if(SZ(r[x])) {
            auto jt = r[x].upper_bound(y);
            if(jt != r[x].begin()) del(x, *prev(jt));
            if(jt != r[x].end()) del(x, *jt);
        }
    }
    int ans = 0;
    FOR(i, n) ans += SZ(r[i]);
    pr2(ans);
}

E

简单容斥+dp, 每次把以 i i i 末尾段中和为 k k k 的段去掉即可.

const int N = 2e5 + 10, inf = 0x3f3f3f3f;
const ll INF = 4E18;
int n;
ll s[N], m, f[N];

void solve() {
    qr(n, m);
    FOR(i, n) qr(s[i]), s[i] += s[i - 1];
    ll sum = f[0] = 1;
    map<ll, int> g;
    g[0] = 1;
    FOR(i, n) {
        f[i] = sum;
        dl(f[i], g[s[i] - m]);
        ad(g[s[i]], f[i]);
        ad(sum, f[i]);
    }
    pr2(f[n]);
}

F

看到最小值最大,显然二分 x x x,判断是否可以每段都 ≥ x \ge x x .
然后环的处理就是断环为链(复制一次在后面).
然后每个位置求一下最大的前驱,满足对应区间和 ≥ x \ge x x.
然后就是倍增选择跳 m m m 次前驱, 如果跳完坐标差 ≤ n \le n n, 则合法.

考虑第二个输出, 不被砍,说明不能以它结尾, 所以统计不合法的 e n d p o i n t endpoint endpoint 数量即可. 复杂度 O ( n log ⁡ m log ⁡ ( ∑ a [ i ] / n ) ) O(n\log m \log (\sum a[i] / n)) O(nlogmlog(a[i]/n)).

当然把倍增去掉,改成 d f s dfs dfs 即可省去 一个 log ⁡ m \log m logm.

const int N = 4e5 + 10, inf = 0x3f3f3f3f;
const ll INF = 4E18;
int n, m, a[N], sum;

int p[N], f[N][20], out;
bool check(int x, int o = 1) {
    int st = 1, s = 0;
    int lg = __lg(m);
    out = 0;
    FOR(i, 2 * n) {
        s += a[i];
        while(st < i && s - a[st] >= x) s -= a[st++];
        p[i] = st - 1;
        f[i][0] = p[i];
        rep(j, 1, lg) f[i][j] = f[f[i][j - 1]][j - 1];
        if(i > n) {
            int j = i;
            rep(k, 0, lg) if(m >> k & 1) j = f[j][k];
            if(i - j <= n) {
                if(o) return 1;
            }
            else out++;
        }
    }
    return 0;
}

void solve() {
    qr(n, m);
    FOR(i, n) qr(a[i]), a[i + n] = a[i], sum += a[i];
    int l = *min_element(a + 1, a + n + 1), r = sum / m, mid;
    while(l < r) {
        mid = (l + r + 1) >> 1;
        if(check(mid)) l = mid;
        else r = mid - 1;
    }
    check(l, 0);
    pr1(l, out);
}

G

口胡.
简单容斥, 所以 a n s = n − ans = n- ans=n 不好的数的数量.
n = ∏ i = 1 m p i c i n = \prod _{i = 1}^m p_i ^{c_i} n=i=1mpici, 则 n n n 不好,当且仅当 ∀ i ∈ [ 1 , m ] , 3 ∤ p i c i + 1 − 1 p i − 1 \forall i \in [1, m], 3 \nmid \dfrac {p_i ^{c_i+ 1}-1}{p_i-1} i[1,m],3pi1pici+11

不妨设记性函数 f ( x ) f(x) f(x), 其中 f ( p c ) = [ 3 ∤ p c + 1 − 1 p − 1 ] ( c + m − 1 m − 1 ) f(p^c) = [3 \nmid \dfrac {p ^{c+ 1}-1}{p-1}] \dbinom {c+m-1}{m-1} f(pc)=[3p1pc+11](m1c+m1). 那么最后结果就是 n − ∑ i = 1 n f ( i ) n-\sum_{i=1}^n f(i) ni=1nf(i).

上min25即可.
对于大质数 p p p, 写个dp, g [ x ] [ t ] g[x][t] g[x][t] 计算 [ 1 , ⌊ n x ⌋ ] [1, \lfloor \dfrac n x\rfloor] [1,xn⌋] m o d    3 \mod 3 mod3 的余数为 t t t 的质数数量即可… (赛时没想到,以为要用什么数论知识 /yun)

  • 21
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值