Codeforces 282E(Sausage Maximization)

来源:互联网 发布:郑州linux运维招聘 编辑:程序博客网 时间:2024/05/19 00:14

题意:给出一段序列,找出一个连续的前缀,一个连续的后缀,使这些数异或出来的值最大。除了前缀或后缀为空以外,前缀和后缀必须包含第一个和最后一个元素。

就是序列a1,a2,a3...an,找出前缀[0,l],后缀[r, n + 1],使这些数异或起来最大,其中r > l,a0和an+1假设它为0,就是说[0,0]表示前缀为空,[n+1,n+1]表示为后缀为空。

思路:这题有点神,没做过类似的题感觉有点难想出来,看了别人的解题报告之后发现,这题真的很神,忍不住把它写上了博客。首先可以将问题转化一下,可以发现序列的所有前缀和后缀都可以在O(n)的时间内求出来,然后问题就转化为了找出两个数异或起来最大,并且它们不能相交,异或起来最大就是尽量让这两个数的各个二进制位异或起来为1;接着字典树就派上用场了,首先我们枚举每一个后缀,在枚举的同时,将与其不相交的前缀插入到字典树中,并对于每一个后缀,我们可以求出和这个异或起来最大且不相交的前缀,至于求这个前缀,我们可以利用点贪心的思想,就是从高位开始枚举,就是越高位越能异或得到1就越好,这样我们就能求出这个前缀了。

#include <cstdio>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;const int N = 100010;const int MAXBITS = 50;LL num[N];struct Node {    int key;    Node *child[2];    Node(){ child[0] = child[1] = NULL; key = 0; }} *root;struct Trie {    void insert(LL val) {        Node *s = root;        for(int i = MAXBITS; i >= 0; i--) {            int dir = ((1LL << i) & val) > 0;            if(s->child[dir] == NULL) {                Node *p = new Node;                p->key = dir;                s->child[dir] = p;            }            s = s->child[dir];        }    }    LL query(LL val) {        LL res = 0;        Node *s = root;        for(int i = MAXBITS; i >= 0; i--) {            int dir = ((1LL << i) & val) > 0;            if(s->child[!dir] != NULL)                s = s->child[!dir];            else                s = s->child[dir];            res += (1LL << i) * s->key;        }        return res;    }} tree;int main() {    int n, i;    cin >> n;    LL prefix = 0, suffix = 0, ans = 0;    for(i = 1; i <= n; i++) {        scanf("%I64d", &num[i]);        suffix ^= num[i];    }    for(i = 1; i <= n + 1; i++) {        tree.insert(prefix);        LL x = tree.query(suffix);        ans = max(ans, (x ^ suffix));        prefix ^= num[i], suffix ^= num[i];    }    cout << ans << endl;    return 0;}



原创粉丝点击