1. 程式人生 > 其它 >Codeforces Round 757 (Div. 2) 解題報告

Codeforces Round 757 (Div. 2) 解題報告

傳送門

\(\rm Codeforces ~ Round ~ 757 ~ (Div. 2)\)

A Divan and a Store

\(n\) 個物品,第 \(i\) 個商品的價格為 \(a_i\)

給你 \(l\)\(r\),表示商人只會選擇價格在 \([l,r]\) 內的物品。

商人有 \(k\) 元錢,問你商人最多可以買多少個商品。

\(T\) 組資料。

對於 \(100\%\) 的資料,保證 \(1\leq T \leq 100,1 \leq n \leq 100,1 \leq l \leq r \leq 10^9,1 \ leq k \leq 10^9,1 \leq a_i \leq 10^9\)

sol

貪心,每次買剩下的價格最小的商品。

首先選出滿足條件的物品,放到優先佇列裡(最小值優先)。

然後一件一件彈出來,計算錢數,若錢數 \(> k\) 或佇列為空,結束程式。

時間複雜度 \(\mathcal O(Tn \log n)\)

#include <bits/stdc++.h>

using namespace std;

#define int long long

int t;

int n, l, r, k;

signed main()
{
    scanf("%lld", &t);
    while (t--)
    {
        scanf("%lld%lld%lld%lld", &n, &l, &r, &k);
        priority_queue<int, vector<int>, greater<int>> q;
        for (int i = 1, a; i <= n; ++i)
        {
            scanf("%lld", &a);
            if (a < l || a > r)
                continue;
            q.push(a);
        }
        int ans = 0, sum = 0;
        while (!q.empty())
        {
            int now = q.top();
            q.pop();
            sum += now;
            // cout << now << "\n";
            if (sum <= k)
                ans++;
            else
                break;
        }
        printf("%lld\n", ans);
    }
    return 0;
}

B Divan and a New Project

在一條街上,蓋 \(n+1\) 棟樓,每棟樓座標為 \(x_i\),滿足 \(\forall j \ne i,x_i \ne x_j\)\(x_i\) 是一個整數。

將所有樓從 \(0\)\(n\) 標號。

有一人在編號為 \(0\) 的樓,分別要去編號為 \(i\) 的建築 \(a_i\) 次,這個人往返編號為 \(i\) 的建築一趟花費的時間為 \(2 \times(|x_i - x_0|)\)

請安排每一棟樓的座標,使得這個人花費的時間最短。

\(T\) 組資料。

對於 \(100\%\) 的資料,保證 \(1\leq T \leq 10^3,1 \leq n \leq 2*10^5,0 \leq a_i \leq 10^6\)

sol

首先,我們把編號為 \(0\) 的樓的座標定為 \(0\) 方便去做。

記答案為 \(ans\),則 \(ans=\sum\limits_{i=1}^{n}{2*a_i*|x_0-x_i|}\)

要使得 \(ans\) 最少,就要讓 \(a_i\) 大的樓放到距離 \(x_0\) 近的地方。

那麼按照 \(a_i\) 從大到小排序,在 \(x_0\) 按照左右左右左右…的順序放樓即可。

具體實現見程式碼。

時間複雜度 \(\mathcal O(Tn)\)

#include <bits/stdc++.h>

using namespace std;

#define int long long

const int _ = 2e5 + 7;

int t;

int n;

struct abc
{
    int v, id;
} a[_];

int b[_];

int ans;

bool cmp(abc a, abc b)
{
    return a.v > b.v;
}

signed main()
{
    scanf("%lld", &t);
    while (t--)
    {
        ans = 0;
        scanf("%lld", &n);
        for (int i = 1; i <= n; ++i)
            scanf("%lld", &a[i].v), a[i].id = i;
        sort(a + 1, a + n + 1, cmp);
        int k = 0;
        for (int i = 1; i <= n; i += 2)
        {
            b[a[i].id] = ++k;
        }
        k = 0;
        for (int i = 2; i <= n; i += 2)
        {
            b[a[i].id] = --k;
        }
        for (int i = 1; i <= n; ++i)
        {
            ans += 2 * a[i].v * abs(b[a[i].id]);
        }
        cout << ans << "\n";
        cout << "0 ";
        for (int i = 1; i <= n; ++i)
            cout << b[i] << " ";
        cout << "\n";
    }
    return 0;
}

C Divan and bitwise operations

有一個未知的序列 \(a\),現知道 \(m\) 個資訊,每個星資訊為 l r x 的形式給出,表示區間 \([l,r]\) 的按位或為 \(x\),保證 \(a\) 中每一個數都被包含在區間 \([l,r]\) 至少一次。

請輸出序列 \(a\) 的所有子序列的異或和 \(\bmod (10^9+7)\)

\(T\) 組資料。

對於 \(100\%\) 的資料,保證 \(1\leq T \leq 10^3,1 \leq n,m \leq 2*10^5,1 \leq l \leq r \leq n,0 \leq x \leq 2^{30}-1\)

sol

顯然,我們可以得到整個序列的按位或就是所有 \(x\) 的按位或,設為 \(S\)

如果 \(S\) 的第 \(i\) 位為 \(0\),貢獻即為 \(0\)

否則總有一個 \(1\),當中恰有一個對應貢獻為 \(2^{i}\),總貢獻為 \(2^{i}\times2^{n-1}\)

那麼 \(Ans=S \times 2^{n-1}\)

時間複雜度 \(\mathcal O(Tn)\)

具體實現見程式碼。

#include <bits/stdc++.h>

#define int long long

using namespace std;

inline int read()
{
    int s = 0, w = 1;
    char c = getchar();
    for (; !isdigit(c); c = getchar())
        if (c == '-')
            w = -1;
    for (; isdigit(c); c = getchar())
        s = (s << 1) + (s << 3) + (c ^ 48);
    return s * w;
}

const int mod = 1e9 + 7;

inline int qpow(int x, int y)
{
    int res = 1;
    while (y)
    {
        if (y & 1)
            res = res * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return res;
}

int T, n, m;

signed main()
{
    T = read();
    while (T--)
    {
        n = read(), m = read();
        int ans = 0;
        while (m--)
        {
            read(), read();
            ans = ans | read();
        }
        ans = ans * qpow(2, n - 1) % mod;
        printf("%lld\n", ans);
    }
    return 0;
}

D Divan and Kostomuksha

給定序列 \(a_1,a_2,...,a_n\),要求重排 \(a\),使得

\[\sum\limits_{i=1}^n \gcd(a_1,a_2,...,a_i) \]

最大。

輸出這個最大值。

sol

顯然,一道 dp

\(cnt_i\) 表示陣列 \(a\) 中是 \(i\) 的倍數的元素個數,\(dp_i\) 表示時能得到已含有因數 \(i\) 結尾排列能獲得的最大值。

此時有轉移方程

\[dp_i=\max_{j=1}{f_{i \times pri_j} + i \times (cnt_i - cnt_{i \times pri_j})} \]

最後答案為滿足 \(cnt_i=n\)\(dp_i\) 的最大值。

\(cnt\) 可先篩出所有質數,再列舉 \(i\) 和質數集 \(pri\),計算 \(cnt_i\)

時間複雜度 \(\mathcal O(w \log \log w)\),其中 \(w\) 為值域。

具體實現見程式碼。

#include <bits/stdc++.h>

using namespace std;

#define int long long

inline int read()
{
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-')
            f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}

const int _ = 2e7 + 1;

int n;

int ans;

int cnt[_ + 7];

int dp[_ + 7];

bool vis[_];

vector<int> primes;

void init()
{
    for (int i = 2; i < _; ++i)
    {
        if (!vis[i])
            primes.push_back(i);
        for (auto p : primes)
        {
            if (p * i > _)
                break;
            vis[p * i] = 1;
            if (i % p == 0)
                break;
        }
    }
}

signed main()
{
    init();
    n = read();
    for (int i = 1, x; i <= n; ++i)
        cnt[read()]++;
    for (auto p : primes)
        for (int j = _ / p; j >= 1; --j)
            cnt[j] += cnt[j * p];
    for (int i = _ - 1; i >= 1; --i)
    {
        dp[i] = cnt[i] * i;
        for (auto p : primes)
        {
            int j = p * i;
            if (j > _)
                break;
            dp[i] = max(dp[i], dp[j] + i * (cnt[i] - cnt[j]));
        }
        if (cnt[i] == n)
            ans = max(ans, dp[i]);
    }
    printf("%lld\n", ans);
    return 0;
}

本文來自部落格園,作者:蒟蒻orz,轉載請註明原文連結:https://www.cnblogs.com/orzz/p/15614936.html