【cf】CodeForces Round 893(Div.2)题解 A - C

A. Buttons

原题链接

题意

有三堆物品,给出每一堆物品的数量,第一个人只能从第一堆和第三堆每次拿一个,第二个人只能从第二堆和第三堆每次拿一个,谁先没东西拿谁就输,问谁能赢

思路

这一题一开始脑子抽了wa了一发,都想让对方输所以都得先拿第三堆的,第三堆拿完了再看第一二堆谁多谁少,注意一下奇偶即可

代码

#include 

using namespace std;

using i64 = long long;

typedef pair<int, int> PII;

void solve()
{
    int a, b, c;
    cin >> a >> b >> c;
    if (c % 2 == 0)
    {
        if (a > b) cout << "First\n";
        else cout << "Second\n";
    }
    else
    {
        if (a >= b) cout << "First\n";
        else cout << "Second\n";
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    int t;
    cin >> t;
    while (t -- )
    {
        solve();
    }
}

B. The Walkway

原题链接

题意

一条路上有几个特殊点,一个人会在以下这几种情况吃一块饼干

  • 经过特殊点
  • 在1点
  • 已经经过k段路程没吃饼干

现在可以删除一个特殊点,问这个人最少吃多少饼干以及有多少种删除方式

思路

我是先计算出每两个特殊点中间的距离可以让这个人吃多少饼干,存储下这个数值的前缀和

之后遍历每个特殊点,计算删除掉这个特殊点之后这个人吃的饼干数量,例如当前计算第 i 个特殊点,那就单独计算第 i-1 个特殊点到第 i+1 个特殊点之间吃的饼干数量,再加上第 i-1 个点前面的饼干数量(计算前缀和时已经将这个数值存储下来了),再加上第 i+1 个点后面的饼干数量,再加上所有特殊点的数量减1

计算时顺便存储一下这个饼干数量被算出过几次

中间有一些需要注意的地方,思路清晰之后主要还是代码实现

代码

#include 

using namespace std;

using i64 = long long;

typedef pair<i64, i64> PII;

void solve()
{
    int n, m, d;
    cin >> n >> m >> d;
    vector<int> seller(m + 1);
    vector<int> idx(m + 1);
    for (int i = 0; i < m; i ++ ) cin >> seller[i];
    seller[m] = n + 1;
    if (seller[0] == 1) idx[0] = 0;
    else idx[0] = (seller[0] - 2) / d + 1;
    for (int i = 1; i <= m; i ++ )
        idx[i] = (seller[i] - seller[i - 1] - 1) / d + idx[i - 1];

    vector<int> ans;
    unordered_map<int, int> cnt;
    ans.push_back(idx[m] - idx[1] + (seller[1] - 2) / d + m);
    cnt[idx[m] - idx[1] + (seller[1] - 2) / d + m] = 1;

    for (int i = 1; i < m; i ++ )
    {
        int res = idx[i - 1] + idx[m] - idx[i + 1] + (seller[i + 1] - seller[i - 1] - 1) / d + m - 1;
        ans.push_back(res);
        if (!cnt.count(res)) cnt[res] = 1;
        else cnt[res] ++ ;
    }

    sort(ans.begin(), ans.end());
    
    cout << ans[0] << ' ' << cnt[ans[0]] << '\n';
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    int t;
    cin >> t;
    while (t -- )
    {
        solve();
    }
}

C. Yet Another Permutation Problem

原题链接

题意

求出一种排列使得相邻两数的最小公约数数量最多

思路

从1开始,让后一个数一直是前一个数的两倍,这样可以保证出现新的最大公约数,直到两倍已经不在给定的n内就换下一个没用过的数

代码

#include 

using namespace std;

using i64 = long long;

typedef pair<int, int> PII;

void solve()
{
    int n;
    cin >> n;
    int i = 2, j = 2, temp;
    vector<bool> idx(n + 1);
    int k = 2;
    vector<int> ans;
    ans.push_back(1);
    ans.push_back(2);
    while (k < n)
    {
        temp = i * j;
        while (temp <= n && !idx[temp])
        {
            ans.push_back(temp);
            k ++ ;
            idx[temp] = true;
            j *= 2 ;
            temp = i * j;
        }
        j = 1;
        i ++ ;
    }
    for (int cnt = 0; cnt < ans.size(); cnt ++ ) cout << ans[cnt] << ' ';
    cout << '\n';
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    int t;
    cin >> t;
    while (t -- )
    {
        solve();
    }
}

你可能感兴趣的:(Codeforces,题解,c语言,算法,开发语言)