Codeforces Round #574 (Div. 2)简要题解

A. Drinks Choosing

分析:优先将成对的处理掉,然后只剩下一堆单个的,除以2向上取整,加起来就是答案。

#include "bits/stdc++.h"

using namespace std;
const int mod = 1e9 + 7;

int a[1004];
unordered_map mp;

int main() {
    int n, k;
    cin >> n >> k;
    for (int i = 0; i < n; ++i) {
        scanf("%d", &a[i]);
        mp[a[i]]++;
    }
    int cnt = 0;
    int ans = 0;
    for (auto it : mp) {
        ans += it.second / 2;
        cnt += it.second % 2;
    }
    ans *= 2;
    ans += (cnt + 1) / 2;
    cout << ans << endl;

}

B. Sport Mafia

分析:设放糖果放了m轮,那么吃了n-m个糖果

k+n-m=(m+1)*m/2

化简得m*(m+3)=2*(n+k)

可以在O(\sqrt{n+k})的时间复杂度内求出。

#include "bits/stdc++.h"

using namespace std;
const int mod = 1e9 + 7;

int a[1004];

int main() {
    long long n, k;
    cin >> n >> k;
    long long x = (n + k) * 2;
    long long ans = 0;
    for (long long i = 1; i * i <= x; ++i) {
        if (i * (i + 3) == x) {
            ans = n - i;
            break;
        }
    }
    cout << ans << endl;

}

C. Basketball Exercise

分析:dp[i][j]表示前i个,最后一个选的是j组的最大值,线性跑一遍就可以了。

#include "bits/stdc++.h"

using namespace std;
const int mod = 1e9 + 7;
long long a[100004];
long long b[100004];
long long dp[100004][2];

int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        scanf("%lld", &a[i]);
    }
    for (int i = 1; i <= n; ++i) {
        scanf("%lld", &b[i]);
    }
    dp[1][0] = a[1];
    dp[1][1] = b[1];
    for (int i = 2; i <= n; ++i) {
        dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + a[i]);
        dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + b[i]);
    }
    cout << max(dp[n][0], dp[n][1]) << endl;
}

D1. Submarine in the Rybinsk Sea (easy edition)

分析:由于位数都是相同的,那么每个数的贡献等于每位依次乘10的奇数次方和偶数次方的和再乘上n。

#include "bits/stdc++.h"

using namespace std;
const int mod = 998244353;
long long a[100004];

int main() {
    long long n;
    cin >> n;
    long long ans = 0LL;
    for (int i = 1; i <= n; ++i) {
        scanf("%lld", &a[i]);
        long long temp = a[i];
        long long base = 1LL;
        while (temp) {
            ans += base * (temp % 10) % mod;
            ans %= mod;
            base *= 100LL;
            base %= mod;
            temp /= 10;
        }
        temp = a[i];
        base = 10;
        while (temp) {
            ans += base * (temp % 10) % mod;
            ans %= mod;
            base *= 100LL;
            base %= mod;
            temp /= 10;
        }
    }
    cout << ans * n % mod << endl;
}

D2. Submarine in the Rybinsk Sea (hard edition)

分析:按照位数分组,最多只有10位,枚举100次就可以了。注意位数不一样的时候,每位的权值也会有所变化。

#include "bits/stdc++.h"

using namespace std;
const int mod = 998244353;

int get_di(long long x) {
    long long ans = 0;
    while (x) {
        ans++;
        x /= 10;
    }
    return ans;
}

long long a[100004][14];
int cnt[14];

int main() {
    long long n;
    cin >> n;
    long long x;
    memset(cnt, 0, sizeof(cnt));
    for (int i = 1; i <= n; ++i) {
        scanf("%lld", &x);
        int d = get_di(x);
        a[cnt[d]++][d] = x;
    }
    long long ans = 0;
    for (int i = 1; i <= 10; ++i) {
        for (int j = 1; j <= 10; ++j) {
            for (int k = 0; k < cnt[i]; ++k) {
                long long base = 1;
                long long temp = a[k][i];
                long long y = j;
                long long sum = 0;
                while (temp) {
                    sum += base * (temp % 10) % mod;
                    sum %= mod;
                    if (y > 0)base *= 100;
                    else base *= 10;
                    base %= mod;
                    temp /= 10;
                    y--;
                }
                base = 10;
                temp = a[k][i];
                y = j - 1;
                while (temp) {
                    sum += base * (temp % 10) % mod;
                    sum %= mod;
                    if (y > 0)base *= 100;
                    else base *= 10;
                    base %= mod;
                    temp /= 10;
                    y--;
                }
                sum *= cnt[j];
                sum %= mod;
                ans += sum;
                ans %= mod;
            }
        }
    }
    cout << ans << endl;
}

E. OpenStreetMap

分析:小数据二维rmq或树套树可做,但这道不行。这个题的特殊点在于每次询问的矩阵大小是固定的。

那么我们首先对于每行,处理出该点(i,j)到(i,j - b+1)中的最小值。

然后再对于每列,由上述求出的数组,找出点(i,j)到(i - a + 1,j)的最小值,就是答案。

用单列队列很容易维护。

#include "bits/stdc++.h"
 
using namespace std;
const int mod = 998244353;
 
long long a[4004][4004];
long long g[4004 * 3004];
 
int main() {
    int n, m, A, B, x, y, z;
    cin >> n >> m >> A >> B >> g[0] >> x >> y >> z;
    for (int i = 1; i <= n * m; ++i) {
        g[i] = (g[i - 1] * x + y) % z;
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            int id = (i - 1) * m + j - 1;
            a[i][j] = (g[id]);
        }
    }
 
    long long ans = 0;
    for (int i = 1; i <= n; ++i) {
        deque>q;
        q.clear();
        for (int j = 1; j <= m; ++j) {
            while(q.size() && q.back().first >= a[i][j])q.pop_back();
            while(q.size() && q.front().second + B - 1 < j)q.pop_front();
            q.push_back({a[i][j],j});
            a[i][j]=q.front().first;
        }
    }
    for (int j = 1; j <= m; ++j) {
        deque>q;q.clear();
        for (int i = 1; i <= n; ++i) {
            while(q.size() && q.back().first >= a[i][j])q.pop_back();
            while(q.size() && q.front().second + A - 1 < i)q.pop_front();
            q.push_back({a[i][j],i});
            if(i>=A&&j>=B)ans += q.front().first;
        }
    }
    cout<

 

你可能感兴趣的:(Codeforces Round #574 (Div. 2)简要题解)