Codeforces Round 901 (Div. 2) A~D

A. Jellyfish and Undertale

直接模拟

#include 
using namespace std;
typedef long long ll;
#define has1 __builtin_popcount
void solve()
{
    long long a, b, n;
    cin >> a >> b >> n;
    long long sum = b;
    for (int i = 0; i < n; i++)
    {
        ll x;
        cin >> x;
        if (x >= a)
        {
            sum += a - 1;
        }
        else
        {
            sum += x;
        }
    }
    cout << sum << "\n";
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

B. Jellyfish and Game

博弈论问题,分操作次数k的奇偶来判断,谁是最后手,不难看出,对于双方操作是有周期性的,赛时想直接猜测最后一次操作换与不换直接求出结果,但是wa了,后面直接对奇偶都取了个特定值,暴力模拟

#include 
using namespace std;
typedef long long ll;
#define has1 __builtin_popcount
void solve()
{
    ll n, m, k, t;
    cin >> n >> m >> k;
    unsigned long long sum1 = 0, ans;
    vector a(n), b(m);
    if (k % 2 == 0)
    {
        k = min((long long)10, k);
    }
    else
    {
        k = min((ll)9, k);
    }
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    for (int i = 0; i < m; i++)
    {
        cin >> b[i];
    }
    sort(a.begin(), a.end());
    sort(b.begin(), b.end());
    for (int i = 0; i < k; i++)
    {
        if (i % 2 == 0)
        {
            if (a[0] < b[m - 1])
            {
                t = a[0];
                a[0] = b[m - 1];
                b[m - 1] = t;
            }
        }
        else
        {
            if (b[0] < a[n - 1])
            {
                t = b[0];
                b[0] = a[n - 1];
                a[n - 1] = t;
            }
        }
        sort(a.begin(), a.end());
        sort(b.begin(), b.end());
    }
    for (int i = 0; i < n; i++)
    {
        // cout << a[i] << " ";
        sum1 += a[i];
    }
    cout << sum1 << endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

C. Jellyfish and Green Apple

求一个s,是否有(2^s)*n%m==0,直接判断是否可分,对于可以分尽的操作,对半切的次数是有限的,直接模拟

#include 
using namespace std;
typedef long long ll;
void solve()
{
    ll n, m;
    cin >> n >> m;
    if (n % m == 0)
    {
        cout << 0 << "\n";
        return;
    }
    if ((n << 32) % m) // 说明经过多次乘2还是无法分尽
    {
        cout << -1 << endl;
        return;
    }
    n %= m;
    ll ans = 0;
    while (true)
    {
        ans += n;
        n = (n * 2) % m;
        if (n == 0)
        {
            cout << ans << "\n";
            return;
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

D. Jellyfish and Mex

一:当mex=0时,删除元素后mex还是0,也就是说,要花费尽量少的代价,将mex转为0

二:当a[i]>mex时,删除此a[i],代价为mex,对于最小的总代价没有好处,不予考虑,故考虑0-mex-1的元素

三、当此时mex=i时,想要mex->j,需要删除掉所有的j,假如j的数量为k,则删除前k-1个后,代价为当时的mex=i,当删除第k个j后,mex=j,即代价为j,此时和删除一个j-1是一样的代价,把它归并到这里即可。

#include 
using namespace std;
typedef long long ll;
#define has1 __builtin_popcount
#define N 5005
int a[N], f[N], k[N];  k[i]表示a数组中值为i的数量,f[i]表示将mex(a数组)变为i时的花费
void solve()
{
    int n;
    cin >> n;
    memset(f, 0x7f7f, sizeof(f));
    memset(k, 0, sizeof(k));
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    sort(a, a + n);
    ll mex = 0; // 初始的mex
    for (int i = 0; i < n; i++)
    {
        if (a[i] == mex) // 如果是有数可以到达mex,说明前面是连续的
        {
            k[mex++] = 1;
        }
        else if (mex > a[i]) // 这样应该是mex=a[i]+1,记录a[i]的数量
        {
            k[a[i]]++;
        }
        else
        {
            break; // a[i]>mex的数都是没有意义的,这样并不会让代价更小
        }
    }
    f[mex] = 0;
    for (int i = mex; i >= 0; i--) // 遍历mex
    {
        for (int j = 0; j < i; j++) // mex从i->j
        {
            f[j] = min(f[j], f[i] + i * (k[j] - (i == mex))); // 如果i==mex,前驱k[j]-1个,mex都是原来的mex,剪掉最后一个后,变为前一个数mex-1,这里的一次就并到那里去
                                                              //             // 如:  值:0 1 2 3 5
                                                              //             //    数量: 1 2 3 4 5
                                                              //             // 初始时mex=4,当mex从4->3时,需要删除所有的4,当删除前3个4时,mex一直为4,删除最后一个4后,mex=3,这里与mex=3,删除一个2是一致的,所以并到那里去就可以了
        }
    }
    cout << f[0] << endl; // 当mex=0时,删除元素后mex依旧是0,代价不变;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

你可能感兴趣的:(算法,c++)