Codeforces Round #636 (Div. 3)

题目传送门

A - Candies

题目大意:找到一个x ,存在k>1,使x + 2x + 4x + ⋯ + 2^(k−1)x = n。

即找到x,k满足这个式子:(2^k-1)*x = n,可以枚举k 判断(2^k-1)|n

#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 main()
{
    int t;
    cin >> t;
    ll n;
    while (t--)
    {
        cin >> n;
        for (ll k = 2; (1 << k) - 1 <= n; k++)
            if (n % ((1 << k) - 1) == 0)
            {
                cout << n / ((1 << k) - 1) << endl;
                break;
            }
    }
}
View Code

 

B. Balanced Array

题目大意,给一个偶数n,构造数列a满足:

1.前n/2个数为偶数

2.后n/2个数为奇数

3.所有数不相同,大于零

4.前n/2个数的和等于后n/2个数

 

因为左右部分的和相同,奇数部分的个数为偶数,因为和为偶数,所以n%4!=0则不可构造,

当n%4==0时,按照 2, 4, …, n-2, n,  1, 3, …, n-3, n+1, n+3, …, n+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++)

int main()
{
    int t, n;
    cin >> t;
    while (t--)
    {
        cin >> n;
        if (n % 4)
            puts("NO");
        else
        {
            puts("YES");
            for (int i = 2; i <= n; i += 2)
                cout << i << " ";
            for (int i = 1; i <= n + 1; i += 2)
                if (i != n / 2 + 1)
                    cout << i << " ";
            cout << endl;
        }
    }
}
View Code

 

C. Alternating Subsequence

题目大意,给一个序列a,最大化长度最大的正负数交错排列的子序列的和。

长度最大即连续的正数或负数之中必须要选一个,那么直接选最大的那个

#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 main()
{
    int t, n;
    ll ans, a, tmp;
    cin >> t;
    while (t--)
    {
        cin >> n;
        ans = 0;
        tmp = 0;
        rep(i, 1, n)
        {
            cin >> a;
            if (tmp * a > 0)
                tmp = max(tmp, a);
            else
            {
                ans += tmp;
                tmp = a;
            }
        }
        cout << ans + tmp << endl;
    }
}
View Code

 

D. Constant Palindrome Sum

题目大意,给一个长度为n的序列a,将a中的值改为中[1,k]任意一个数,满足i∈[1,n/2] ai+an-i+1 = x值相等,求最小的修改次数。

可以发现对于每一对数,修改次数为0,1,2,由x决定

    [ 2, min(a[i], a[n-i+1]) ]                             2次

    [ min(a[i], a[n-i+1])+1, a[i]+a[n-i+1]-1 ]     1次

    a[i]+a[n-i+1]                                              0次

    [ a[i]+a[n-i+1]+1,max(a[i], a[n-i+1])+k ]     1次

    [ max(a[i], a[n-i+1])+k+1, 2*k ]                  2次

枚举x∈[2,k * 2],遍历a数组,求得最小的修改次数,复杂度O(nk),显然不行

因为修改次数区间是连续的,可以用线段树或者树状数组来维护x∈[2,k * 2]的修改次数

#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 n, k, ans, a[200010];

int c[400010];
int lowbit(int x)
{
    return x & (-x);
}

void update(int x, int d)
{
    while (x <= 2 * k + 1)
    {
        c[x] += d;
        x += lowbit(x);
    }
}

int getsum(int x)
{
    int tmp = 0;
    while (x)
    {
        tmp += c[x];
        x -= lowbit(x);
    }
    return tmp;
}

int main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        cin >> n >> k;
        rep(i, 1, n) cin >> a[i];
        rep(i, 1, k * 2 + 1) c[i] = 0;
        rep(i, 1, n / 2)
        {
            update(2, 2);
            update(min(a[i], a[n - i + 1]) + 1, -1);
            update(a[i] + a[n - i + 1], -1);
            update(a[i] + a[n - i + 1] + 1, 1);
            update(max(a[i], a[n - i + 1]) + k + 1, 1);
            update(2 * k + 1, -2);
        }
        ans = n;
        rep(i, 2, 2 * k)
            ans = min(ans, getsum(i));
        cout << ans << endl;
    }
}
View Code

 

E. Weights Distributing

题目大意,给定无向无权图,给图加权值,使a->b,b->c代价最小

设a->b经过x,如果b->c经过x,那么一定是延a->x->b的方向返回至x,就可以理解成a->x->b->x->c

枚举x,求dis(a,x) + 2*dis(b,x) + dis(c,x)最小值,中间求个前缀和就行了

#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 n, m, a, b, c;
ll p[200010], ans;

struct node
{
    int to, next;
} e[400010];
int id = 0, head[200010];
int disa[200010], disb[200010], disc[200010];
void add(int x, int y)
{
    id++;
    e[id].to = y;
    e[id].next = head[x];
    head[x] = id;
}
int main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t, u, v;
    cin >> t;
    while (t--)
    {
        id = 0;
        memset(head, 0, sizeof(head));
        cin >> n >> m >> a >> b >> c;
        rep(i, 1, m) cin >> p[i];
        sort(p + 1, p + m + 1);
        rep(i, 1, m) p[i] += p[i - 1];
        rep(i, 1, m)
        {
            cin >> u >> v;
            add(u, v);
            add(v, u);
        }
        rep(i, 1, n) disa[i] = disb[i] = disc[i] = -1;
        queue<int> q;
        q.push(a);
        disa[a] = 0;
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            for (int i = head[u]; i; i = e[i].next)
                if (disa[e[i].to] == -1)
                {
                    disa[e[i].to] = disa[u] + 1;
                    q.push(e[i].to);
                }
        }
        q.push(b);
        disb[b] = 0;
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            for (int i = head[u]; i; i = e[i].next)
                if (disb[e[i].to] == -1)
                {
                    disb[e[i].to] = disb[u] + 1;
                    q.push(e[i].to);
                }
        }
        q.push(c);
        disc[c] = 0;
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            for (int i = head[u]; i; i = e[i].next)
                if (disc[e[i].to] == -1)
                {
                    disc[e[i].to] = disc[u] + 1;
                    q.push(e[i].to);
                }
        }
        ans = p[m] * 2;
        rep(i, 1, n) if (disa[i] + disb[i] + disc[i] <= m) ans = min(ans, p[disb[i]] + p[disa[i] + disb[i] + disc[i]]);
        cout << ans << endl;
    }
}
View Code

 

posted @ 2020-04-22 12:42  若讷  阅读(228)  评论(0编辑  收藏  举报