Educational Codeforces Round 6 A.B.C.D.E

A. Professor GukiZ’s Robot

题意

robot可以走八个方向。给出起点坐标和终点坐标,问最少要走几次。

思路

最优当然是尽可能的斜着走喽。

code

cout << max(abs(x_1 - x_2), abs(y_1 - y_2)) << endl;


B. Grandfather Dovlet’s calculator

题意

max用计算器从数字a按倒数字b,问计算器显示了多少segments

思路

暴力循环a~b,然后数位分离并累加。

code

for (int s = x; s <= y; s++) {

    int tmp = s;

    while (tmp) {
        ans += 1LL * a[tmp % 10];
        tmp /= 10;
    }
}

C. Pearls in a Row

题意

一个数组中连续的序列称为一个段,一个段中有至少两个数字相同称为好的段,问给出的数组最多能被分成多少个段,要求不重不漏。

思路

贪心,从左往右找,一旦发现数字重复出现过立即分一个段出来,直到分完。注意要让最后一个段包含后面所有的数字。

code

#include<bits/stdc++.h>
using namespace std;

int n, cnt, l;
int a[300000 + 5];
map<int, int > m;
vector<pair<int, int> > v;

int main () {

    scanf ("%d", &n);
    l = 1;
    for (int i=1; i<=n; i++) {
        scanf ("%d", &a[i]);
        if (m[a[i]] == 0) {
            m[a[i]] = i;
        } else {
            cnt++;
            v.push_back(make_pair(l, i));
            l = i+1;
            m.clear();
        }
    }

    if (cnt != 0) {
        printf ("%d\n",cnt);
        for (int i=0; i<cnt-1; i++) {
            printf ("%d %d\n", v[i].first, v[i].second);
        }
        printf ("%d %d\n", v[cnt-1].first, n);
    } else printf ("-1\n");

    return 0;
}

D. Professor GukiZ and Two Arrays

题意

对于a,b两个数组,最多交换两个数字使得他们数组元素的和的差的绝对值最小。

思路

分三种情况

交换0次
直接计算差值。

交换1词
枚举两个数组交换的值。

交换2次
对b数组找出所有交换两次的方案并排序。
枚举a数组要换的两个数
在b数组中二分找最优的解
应为是绝对值,所以该解的前后也有可能更优

code

#include <bits/stdc++.h>
using namespace std;

const int INF = 999999999;
const int MAXN = 2000 + 5;

int n, m;
long long a[MAXN], b[MAXN];
long long sum_a, sum_b;

long long val_zero = INF;

void solve_zero () {
    val_zero = abs(sum_a - sum_b);
}

long long val_one = INF;
int ans_one_a = -1, ans_one_b = -1;

void solve_one () {

    val_one = abs(sum_a - sum_b);

    for (int i=1; i<=n; i++) {
        for (int j=1; j<=m; j++) {

            long long tmp_a = sum_a - a[i] + b[j];
            long long tmp_b = sum_b - b[j] + a[i];

            if (abs(tmp_a - tmp_b) < val_one) {

                val_one = abs(tmp_a - tmp_b);
                ans_one_a = i;
                ans_one_b = j;                
            }
        }
    }
}

struct Node { 

    long long val;
    int pos_i, pos_j;
    Node(){}
    Node (long long va, int pi, int pj) {
        val = va;
        pos_i = pi;
        pos_j = pj;
    }
}c[MAXN * MAXN];

bool cmp (Node a, Node b) {
    return a.val < b.val;
}

int k=0;
long long val_two = INF;
pair<int, int> ans_two_a = make_pair(-1, -1);
pair<int, int> ans_two_b = make_pair(-1, -1);

void solve_two () {

    val_two = abs(sum_a - sum_b);

    for (int i=1; i<=m; i++) {
        for (int j=i+1; j<=m; j++) {
            c[k++] = Node(b[i] + b[j], i, j);
        }
    }

    sort(c, c+k, cmp);

    for (int i=1; i<=n; i++) {
        for (int j=i+1; j<=n; j++) {

            long long aa = a[i] + a[j];

            Node bb = Node ((sum_b - sum_a + 2 * aa) / 2, i, j);

            int p = lower_bound(c, c+k, bb, cmp) - c;

            if (p >= 0 && p < k) {
                if (abs(sum_a - 2 * aa - sum_b + 2 * c[p].val) < val_two) {
                    val_two = abs(sum_a - 2 * aa - sum_b + 2 * c[p].val);
                    ans_two_a = make_pair(i, j);
                    ans_two_b = make_pair(c[p].pos_i, c[p].pos_j);
                }
            }

            if (p > 0) {
                if (abs(sum_a - 2 * aa - sum_b + 2 * c[p-1].val) < val_two) {
                    val_two = abs(sum_a - 2 * aa - sum_b + 2 * c[p-1].val);
                    ans_two_a = make_pair(i, j);
                    ans_two_b = make_pair(c[p-1].pos_i, c[p-1].pos_j);
                }
            }

            if (p < k-1) {
                if (abs(sum_a - 2 * aa - sum_b + 2 * c[p+1].val) < val_two) {
                    val_two = abs(sum_a - 2 * aa - sum_b + 2 * c[p+1].val);
                    ans_two_a = make_pair(i, j);
                    ans_two_b = make_pair(c[p+1].pos_i, c[p+1].pos_j);
                }
            }
        }
    }
}

int main () {

    scanf ("%d", &n);
    for (int i=1; i<=n; i++) {
        scanf ("%I64d", &a[i]);
        sum_a += a[i];
    }

    scanf ("%d", &m);
    for (int i=1; i<=m; i++) {
        scanf ("%I64d", &b[i]);
        sum_b += b[i];
    }

    solve_zero();
    solve_one ();
    solve_two ();

    if (val_zero <= val_one && val_zero <= val_two) {
        printf ("%I64d\n0\n", val_zero);
    } else if (val_one <= val_zero && val_one <= val_two) {
        printf("%I64d\n1\n", val_one);
        printf("%d %d\n", ans_one_a, ans_one_b);
    } else if (val_two <= val_zero && val_two <= val_one) {
        printf("%I64d\n2\n", val_two);
        printf("%d %d\n", ans_two_a.first, ans_two_b.first);
        printf("%d %d\n", ans_two_a.second, ans_two_b.second);
    }

    return 0;
}

Update in 23:19 2016-1-28


E. New Year Tree

题意

Resha 有棵树,树的每个节点都有一种颜色,现在给出两种操作

  1. 把某个子树的所有节点的颜色修改为s
  2. 查询某个节点所在子树的颜色种数

思路

这题看起来难,实则不然。

对于一棵树妖对其子树操作,我们很容易想到他的dfs序列。因为在dfs序列中,一棵子树对应着序列的一个子串。(我们其实并不需要找出该序列,只需知道每个节点的子树在序列的起始和终点位置)

由此问题转换为对一个序列的区间查询和修改操作。可以用线段树很好的解决。而颜色的问题,我们可以用long long保存信息,每个二进制位表示是否有改该颜色。

于是,问题就解决了,码代码时多注意下就行。

code

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 400000 + 5;

int n, m;
long long c[MAXN];

vector<int > v[MAXN];

struct Node {
    int l, r;
    Node() {}
    Node (int _l, int _r) {
        l = _l;
        r = _r;
    }
}tc[MAXN];

long long bc[MAXN];

int dfs_counter = 1;
void dfs(int t, int fa) {

    tc[t].l = dfs_counter;

    for (int i=0; i<v[t].size(); i++) {
        if (v[t][i] == fa) continue;
        dfs(v[t][i], t);
    }

    tc[t].r = dfs_counter;

    bc[dfs_counter] = c[t];

    dfs_counter++;
}

long long sg[MAXN * 4];
long long lz[MAXN * 4];

struct Sgment {

    Sgment() {
        memset (sg,  0, sizeof sg);
        memset (lz, -1, sizeof lz);
    }

    void push_up(int lr) {
        sg[lr] = sg[lr<<1] | sg[lr<<1|1];
    }

    void push_down (int lr) {
        if (lz[lr] != -1) {
            lz[lr<<1] = lz[lr];
            lz[lr<<1|1] = lz[lr];
            sg[lr<<1] = lz[lr];
            sg[lr<<1|1] = lz[lr];
            lz[lr] = -1;
        }
    }

    void create(int l, int r, int lr) {
        if (l == r) {
            sg[lr] = 1LL << bc[l];
            return ;
        } 
        int m = (l + r) / 2;
        create (l, m, lr<<1);
        create (m+1, r, lr<<1|1);
        push_up (lr);
    }

    void update (int l, int r, int lr, int L, int R, long long s) {
        if (l >= L && r <= R) {
            sg[lr] = s;
            lz[lr] = s;
            return ;
        }

        push_down (lr);

        int m = (l + r) / 2;
        if (m >= L) update(l, m, lr<<1, L, R, s);
        if (m <  R) update(m+1, r, lr<<1|1, L, R, s);

        push_up (lr);
    }

    long long query (int l, int r, int lr, int L, int R) {
        if (l >= L && r <= R) {
            return sg[lr];
        }

        push_down (lr);

        long long res = 0;

        int m = (l + r) / 2;

        if (m >= L) res |= query (l, m, lr<<1, L, R);
        if (m <  R) res |= query (m+1, r, lr<<1|1, L, R);

        return res;
    }
};


int main () {
    scanf ("%d %d", &n, &m);

    for (int i=1; i<=n; i++) {
        scanf ("%I64d", &c[i]);
    }

    int tmpa, tmpb;
    for (int i=1; i<n; i++) {
        scanf ("%d %d", &tmpa, &tmpb);
        v[tmpa].push_back(tmpb);
        v[tmpb].push_back(tmpa);
    }

    dfs(1, -1);

    Sgment sg;
    sg.create(1, n, 1);

    int op, a, b;

    for (int s=0; s<m; s++) {
        scanf ("%d", &op);// cout << "op " << op << endl;

        if (op == 1) {
            scanf ("%d %d", &a, &b);
            sg.update(1, n, 1, tc[a].l, tc[a].r, 1LL<<b);

        } else {
            scanf ("%d", &a);
            long long ans = sg.query(1, n, 1, tc[a].l, tc[a].r);
            // printf ("ans = %d\n",ans);
            int cnt = 0;
            for(int i=1; i<=60; i++) {
                if ((ans & (1LL << i)) != 0) cnt++;
            }

            printf ("%d\n", cnt);
        }
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值