Divide by Zero 2021 and Codeforces Round #714 (Div. 2)

Divide by Zero 2021 and Codeforces Round #714 (Div. 2)

A - Array and Peaks

int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n >> m; set<int> st;
        if ((n - 1) / 2 < m) { cout << "-1
"; continue; }
        rep (i, 2, n) st.insert(i); cout << 1 << ' ';
        while (m) {
            auto it = st.begin(); ++it;
            cout << *it << ' ' << *st.begin() << ' ';
            st.erase(st.begin()); st.erase(st.begin()); --m;
        }
        for (auto &i : st) cout << i << ' '; cout << '
';
    }
    return 0;
}

B - AND Sequences

由题意得(x & z = y, x = z & y)

(x >= x & z = y, y >= z & y = x)(x = y 且 x & z = y & z = x = y)

int a[30];
ll s[N];
 
int main() {
    IOS; s[0] = 1;
    rep (i, 1, 2e5) s[i] = s[i - 1] * i % mod;
    for (cin >> _; _; --_) {
        cin >> n; map<int, ll> st; memset(a, 0, sizeof a);
        rep (i, 1, n) {
            cin >> m, ++st[m];
            rep (j, 0, 29) if (m >> j & 1) ++a[j];
        }
        ll ans = 0;
        for (auto &p : st) {
            bool f = 1;
            rep (j, 0, 29) if ((p.fi >> j & 1) && a[j] != n) f = 0;
            if (f) ans = (ans + p.se * (p.se - 1) % mod) % mod;
        }
        cout << ans * s[n - 2] % mod << '
';
    }
    return 0;
}

C - Add One

dp (f(i, j)) 表示从0开始经过(i)次增加, 数字(j)有几个

int f[N][10];
 
int main() {
    IOS; f[0][0] = 1;
    rep (i, 1, 2e5 + 10) {
        f[i][0] = f[i - 1][9], f[i][1] = (f[i - 1][9] + f[i - 1][0]) % mod;
        rep (j, 2, 9) f[i][j] = f[i - 1][j - 1];
    }
    for (cin >> _; _; --_) {
        cin >> n >> m; int ans = 0;
        for (; n; n /= 10) rep (i, 0, 9) ans = (ans + f[m + n % 10][i]) % mod;
        cout << ans << '
';
    }
    return 0;
}

D - GCD and MST

注意到(gcd(a([l, r])) = a[i])则必有(min(a([l, r]))=a[i]), 枚举区间就行了

int a[N];
PII b[N];
bool v[N];
 
int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n >> m; ll ans = 0; k = n - 1;
        rep (i, 1, n) cin >> a[i], b[i] = { a[i], i }, v[i] = 0; sort(b + 1, b + 1 + n);
        rep (i, 1, n) if (!v[b[i].se]) {
            if (b[i].fi >= m) break;
            int l = b[i].se, r = b[i].se;
            while (l > 1 && !v[l] && a[l - 1] % b[i].fi == 0) --l;
            while (r < n && !v[r] && a[r + 1] % b[i].fi == 0) ++r;
            k -= r - l; rep (j, l, r) v[j] = 1; ans += (ll)(r - l) * b[i].fi;
        }
        ans += (ll)k * m; cout << ans << '
';
    }
    return 0;
}

E - Cost Equilibrium

先判断是否存在

然后当要增大(减小)的数 == 1时, 直接去重全排列,

否则要增大的数,要减小的数, 必定各自为营, 不存在相互交叉

否则最大最小价值不一样

当两者无交叉的时候, 要增大的数内之际无论怎么操作, 最后都等价于要减小的数让其变大(相当于均摊纸牌)

注意相同的数去重就行

const int N = 1e5 + 5, mod = 1e9 + 7;
 
int n, m, _, k, cas;
ll fac[N], facinv[N], inv[N];
int a[N];
 
void init(int n) {
    fac[0] = fac[1] = facinv[0] = facinv[1] = inv[0] = inv[1] = 1;
    rep(i, 2, n)
        fac[i] = fac[i - 1] * i % mod,
        inv[i] = inv[mod % i] * (mod - mod / i) % mod,
        facinv[i] = facinv[i - 1] * inv[i] % mod;
}
 
int main() {
    IOS; cin >> n; init(n); ll s = 0;
    rep(i, 1, n) cin >> a[i], s += a[i];
    if (s % n) return cout << 0, 0;
    sort(a + 1, a + 1 + n); s /= n;
    int l = lower_bound(a + 1, a + 1 + n, s) - a, r = upper_bound(a + 1, a + 1 + n, s) - a - 1;
    if (l == 1 && r == n) return cout << 1, 0;
    ll x = fac[l - 1], y = fac[n - r], ans = fac[n] * facinv[r - l + 1] % mod * facinv[n - r + l - 1] % mod;
    for (int i = 1, c = 0; i < l; ++i, ++c) if (a[i] != a[i + 1]) x = x * facinv[++c] % mod, c = -1;
    for (int i = n, c = 0; i > r; --i, ++c) if (a[i] != a[i - 1]) y = y * facinv[++c] % mod, c = -1;
    if (l == 2) cout << ans * y % mod * (n - r + l - 1) % mod;
    else if (r == n - 1) cout << ans * x % mod * l % mod;
    else cout << ans * x % mod * y % mod * 2 % mod;
    return 0;
}

原文地址:https://www.cnblogs.com/2aptx4869/p/14651263.html