Codeforces Round #638 (Div. 2)

题目传送门

A. Phoenix and Balance

将21,22,...,2n分成数量相等的两堆,使两堆和的差值最小

数据也不大,挺简单的

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, b) for (register int i = a; i <= b; i++)
 
int t, n;
ll cnt[40];
int main()
{
    cnt[1] = 2;
    rep(i, 2, 30) cnt[i] = cnt[i - 1] * 2;
    cin >> t;
    while (t--)
    {
        cin >> n;
        ll cnt1 = 0, cnt2 = 0, ans1 = 0, ans2 = 0;
        for (int i = n; i; i--)
        {
            if ((ans1 <= ans2 && cnt1 < n / 2) || cnt2 == n / 2)
            {
                cnt1++;
                ans1 += cnt[i];
            }
            else
            {
                cnt2++;
                ans2 += cnt[i];
            }
        }
        cout << abs(ans1 - ans2) << endl;
    }
}
View Code

 

B. Phoenix and Beauty

通过在原数组插值构建beautiful array。

题目一直在强调不需要最小化m。可以构造一个长度为k的数组,输出n次,不成立的情况是原数组的数的种类大于k。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, b) for (register int i = a; i <= b; i++)
 
int t, k, n, a[110];
int vis[110], cnt;
int main()
{
    cin >> t;
    while (t--)
    {
 
        cin >> n >> k;
        cnt = 0;
        rep(i, 1, n) vis[i] = 0;
        rep(i, 1, n)
        {
            cin >> a[i];
            if (!vis[a[i]])
            {
                vis[a[i]] = 1;
                cnt++;
            }
        }
        if (cnt > k)
            puts("-1");
        else
        {
            cout << k * n << endl;
            rep(i, 1, n)
            {
                rep(j, 1, n) if (vis[j]) cout << j << " ";
                for (int j = 1, id = 1; id <= k - cnt; j++)
                    if (!vis[j])
                    {
                        id++;
                        cout << j << " ";
                    }
            }
            cout << endl;
        }
    }
}
View Code

 

C题卡住了

 

D. Phoenix and Science

第一天有1团1个细菌,每团细菌每一天可能分裂为一半,也有可能不分裂。每团细菌每晚上+1个细菌,求细菌总数到达n的最小天数,还要写出分裂情况。

先计算天数。

设weight[0]=1,weight[1]=2,weight[2]=4... 为每天细菌的团数,那么Σ(1,x)weight[i]即为到达第x天时细菌总数,找到第一个使前缀和大于等于n的i

求得天数d为log2(n+1)-1向上取整。(其实具体计算没必要)

然后考虑每天的变化,变化就是weight数组的差分

在满足weight[i]∈(weight[i-1],weight[i-1]*2)的情况下适当减小就可以了

因为Σ(1,d-1)weight[i]<n,所以Σ(1,d)weight[i]-n>Σ(1,d-1)weight[i]

我们可以从第x天开始倒着减小weight[i-1]的值直到满足条件

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, b) for (register int i = a; i <= b; i++)

ll t, n;
ll mi[40];
ll d, weight[40];

int main()
{
    mi[0] = 1;
    for (int i = 1; i <= 30; i++)
    {
        mi[i] = mi[i - 1] * 2;
        if (mi[i] >= 1e9)
            break;
    }
    cin >> t;
    while (t--)
    {
        cin >> n;
        if (n == 1)
        {
            puts("1\n0");
            continue;
        }
        for (d = 0;; d++)
        {
            weight[d] = mi[d];
            if (mi[d + 1] - 1 >= n)
                break;
        }
        ll dec = mi[d + 1] - 1 - n;
        for (int i = d;; i--)
        {
            if (weight[i - 1] < dec)
            {
                weight[i] -= weight[i - 1];
                dec -= weight[i - 1];
            }
            else
            {
                weight[i] -= dec;
                break;
            }
        }
        cout << d << endl;
        rep(i, 1, d) cout << weight[i] - weight[i - 1] << " ";
        cout << endl;
    }
}
View Code

 

posted @ 2020-05-02 18:31  若讷  阅读(223)  评论(0编辑  收藏  举报