Codeforces Intel Code Challenge Elimination Round(Oct/01/2016)

本文解析了两道经典的算法题目,第一题通过逆向思维和并查集的方法求解数列变化后子数列和的最大值;第二题利用贪心算法和搜索技巧解决集合变换问题,寻找变化路径以达到目标集合。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C
大意就是给定一个数列,每次使一个数变成0,求每次变化以后不包括零的子数列的和的最大值是多少。

可以逆推。
这让我想到了以前的一道题

http://blog.youkuaiyun.com/vectorxj/article/details/51477089 就是将问题反过来求并查集。

这道题其实道理也类似,问题就转化成每次加入一个数,求不包括零的子数列的和的最大值是多少。就需要用两个数组li,ri来存储当前已有的合法子数列的边界。另外,反过来以后答案肯定是不下降的,所以可以直接取max

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <queue>
using namespace std;

typedef long long ll;

inline char get(void) {
    static char buf[100000], *p1 = buf, *p2 = buf;
    if (p1 == p2) {
        p2 = (p1 = buf) + fread(buf, 1, 100000, stdin);
        if (p1 == p2) return EOF;
    }
    return *p1++;
}
template<typename T>
inline int read(T &x) {
    static char c; x = 0;
    for (c = get(); c < '0' || c > '9'; c = get());
    for (; c >= '0' && c <= '9'; x = x * 10 + c - '0', c = get());
    return x;
}
inline ll Max(ll a, ll b) {
    return a > b ? a : b;
}

const int N = 100010, INF = 1 << 30;

int q[N], l[N], r[N];
ll num[N], ans[N];
int n, x, y, p;

int main(void) {
    read(n);
    for (int i = 1; i <= n; i++) {
        read(num[i]); num[i] += num[i - 1];
        l[i] = r[i] = i;
    }
    for (int i = 0; i < n; i++) read(q[i]);
    for (int i = n - 1; i; i--) {
        p = q[i]; x = l[p - 1];
        if (l[p + 1] == p) y = r[p + 1];
        else y = p;
        ans[i] = Max(ans[i + 1], num[y] - num[x]);
        l[y] = l[p] = x; r[x + 1] = y;
    }
    for (int i = 1; i <= n; i++) printf("%I64d\n", ans[i]);
    return 0;
}

D
两种变换:

1.Take any integer xi and multiply it by two, i.e. replace xi with 2·xi.
2.Take any integer xi, multiply it by two and add one, i.e. replace xi with 2·xi + 1.

问一个集合能否能由另一个集合变化而来,且该集合的元素最大值最小。
感觉很简单吧。贪心加搜索搞一搞就好了,每次找到最大值取出不断判断除以二之后的值是否属于集合即可。原理很好想。

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <set>
using namespace std;

inline char get(void) {
    static char buf[100000], *p1 = buf, *p2 = buf;
    if (p1 == p2) {
        p2 = (p1 = buf) + fread(buf, 1, 100000, stdin);
        if (p1 == p2) return EOF;
    }
    return *p1++;
}
template<typename T>
inline int read(T &x) {
    static char c; x = 0;
    for (c = get(); c < '0' || c > '9'; c = get());
    for (; c >= '0' && c <= '9'; x = x * 10 + c - '0', c = get());
    return x;
}

const int N = 50010;

struct cmp {
    bool operator ()(int a, int b) {
        return a > b;
    }
};
typedef set<int, cmp> ms;
ms S;
int n, x, a[N];

inline void Modify(int x) {
    S.erase(S.find(x)); S.insert(x >> 1);
}
bool check(int x) {
    if (!(x >> 1)) return false;
    if (S.find(x >> 1) != S.end()) {
        bool b = check(x >> 1);
        if (b) Modify(x);
        return b;
    }
    Modify(x);
    return true;
}

int main(void) {
    read(n);
    for (int i = 1; i <= n; i++) S.insert(read(a[i]));
    while (1) {
        x = *S.begin();
        if (!check(x)) break;
    }
    for (ms::iterator i = S.begin(); i != S.end(); i++)
        printf("%d ", *i);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值