Codeforces Round #636 (Div. 3)

Codeforces Round #636 (Div. 3)(2020.4.21)

A、Candies

因为题目保证了有解,所以我们枚举一下 k k k就行了。

#include 
using namespace std;
typedef long long ll;
int main()
{
    int t; cin >> t;
    while (t--)
    {
        ll n; cin >> n;
        ll sum = 4;
        while (n % (sum - 1) != 0)
            sum *= 2;
        cout << n / (sum - 1) << endl;
    }
    return 0;
}

B、Balanced Array

看起来有点吓人,其实也很好想。看样例就能看出来。

首先如果 n / 2 n/2 n/2是奇数肯定不成立。前面是偶数,后面是奇数,不相等。

如果 n / 2 n/2 n/2是偶数我们就尝试构造。偶数就 2 , 4 , 6 , 8 2,4,6,8 2,4,6,8这样输出,奇数就 1 , 3 , 5 , 7 1,3,5,7 1,3,5,7这样输出。然后在最后一个数把前面的差补全就好了。

#include 
using namespace std;
typedef long long ll;
int main()
{
    int t; cin >> t;
    while (t--)
    {
        int n; scanf("%d", &n);
        if (n / 2 % 2) printf("NO\n");
        else
        {
            printf("YES\n");
            for (int i = 1; i <= n / 2; ++i)
                printf("%d ", 2 * i);
            for (int i = 1; i <= n / 2 - 1; ++i)
                printf("%d ", 2 * i - 1);
            printf("%d\n", n / 2 * 3 - 1);
        }
    }
    return 0;
}

C、Alternating Subsequence

这题因为限制要找最长的,所以我们见到异号的就加就可以了。

如果同号的话更新一下最大值。

#include 
using namespace std;
typedef long long ll;
int main()
{
    int t; cin >> t;
    while (t--)
    {
        int n; cin >> n;
        static ll a[200010];
        for (int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
        vector <ll> sav; ll sum = a[1];
        sav.push_back(a[1]);
        for (int i = 2; i <= n; ++i)
        {
            int size = sav.size();
            if (sav[size - 1] * a[i] > 0)
            {
                if (sav[size - 1] < a[i])
                {
                    sum = sum - sav[size - 1] + a[i];
                    sav[size - 1] = a[i];
                }
            }
            else sav.push_back(a[i]), sum += a[i];
        }
        printf("%lld\n", sum);
    }
    return 0;
}

这场没想到的是D居然没出。思路在接近一个月前是接触过的,不过比赛没想到。明天会补。

不过这次因为前三题出得飞快居然上了70分。舒服了。

不过罚坐了一个半小时多

今天是个上分的好天气 真的

D、Constant Palindrome Sum(2020.4.23 补)

差分前缀和。比赛的时候想的是枚举 x x x,考虑这个 x x x有哪几种数对会对它有贡献。两个数都大于等于 x x x贡献为2,剩下的除非等于其它贡献都为1。不过这真的没办法写…

正解也是枚举 x x x,不过考虑的是每对数对 x x x的贡献。观察发现对于某对数 ( a , b ) (a,b) (a,b),修改其中某一个数的值最小能改成 m i n ( a , b ) + 1 min(a,b)+1 min(a,b)+1,最大能改成 m a x ( a , b ) + k max(a,b)+k max(a,b)+k。于是在这个区间里这对数的贡献为1。不过 a + b a+b a+b的贡献记得修改为0。

在这个区间之外的贡献都为2。然后我们就可以差分了。

对于在区间外的贡献我们考虑在 d i f [ 1 ] dif[1] dif[1]中加二。然后直接跑一遍前缀和,取个最小值。

(过几天也出道差分的题玩玩www)

#include 
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 10;
const int INF = 0x3f3f3f3f;
int main()
{
    int t; cin >> t;
    while (t--)
    {
        int n, k; scanf("%d%d", &n, &k);
        static int a[MAXN];
        for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
        int dif[2 * MAXN] = {0};
        for (int i = 1; i <= n / 2; ++i)
        {
            dif[1] += 2;
            dif[min(a[i], a[n - i + 1]) + 1]--;
            dif[max(a[i], a[n - i + 1]) + k + 1]++;
            dif[a[i] + a[n - i + 1]]--;
            dif[a[i] + a[n - i + 1] + 1]++;
        }
        int ans = INF;
        for (int i = 1; i <= 2 * k; ++i)
            dif[i] = dif[i - 1] + dif[i], ans = min(ans, dif[i]);
        cout << ans << endl;
    }
    return 0;
}

这题还有一点需要注意。 d i f dif dif数组这种需要初始化的如果空间够尽量不要开到static里。

对于大数组memset的时间消耗非!常!大!

之前听说fill_n跑得很快。不清楚是不是真的。

一开始开到static里+memset时间是982ms,差一点就超时了。

删掉memset之后直接降到545ms,快了接近一倍。

你可能感兴趣的:(Codeforces Round #636 (Div. 3))