zoukankan      html  css  js  c++  java
  • [BZOJ4408][Fjoi 2016]神秘数

    [BZOJ4408][Fjoi 2016]神秘数

    试题描述

    一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数。例如S={1,1,1,4,13},
    1 = 1
    2 = 1+1
    3 = 1+1+1
    4 = 4
    5 = 4+1
    6 = 4+1+1
    7 = 4+1+1+1
    8无法表示为集合S的子集的和,故集合S的神秘数为8。
    现给定n个正整数a[1]..a[n],m个询问,每次询问给定一个区间[l,r](l<=r),求由a[l],a[l+1],…,a[r]所构成的可重复数字集合的神秘数。

    输入

    第一行一个整数n,表示数字个数。
    第二行n个整数,从1编号。
    第三行一个整数m,表示询问个数。
    以下m行,每行一对整数l,r,表示一个询问。

    输出

    对于每个询问,输出一行对应的答案。

    输入示例

    5
    1 2 4 9 10
    5
    1 1
    1 2
    1 3
    1 4
    1 5

    输出示例

    2
    4
    8
    8
    8

    数据规模及约定

    对于100%的数据点,n,m <= 100000,∑a[i] <= 10^9

    题解

    一开始把神秘数 ans 设为 1,然后大小在 [0, ans] 范围中所有数显然都是可以用的,并且它们所能组成的最大数就是所有数之和 sum,于是 ans = sum + 1,重复以上动作。因为每次 ans 至少倍增,所以操作次数不超过 9·log210。

    操作可以用线段树套 treap 实现,像这样:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    
    const int BufferSize = 1 << 16;
    char buffer[BufferSize], *Head, *Tail;
    inline char Getchar() {
        if(Head == Tail) {
            int l = fread(buffer, 1, BufferSize, stdin);
            Tail = (Head = buffer) + l;
        }
        return *Head++;
    }
    int read() {
        int x = 0, f = 1; char c = Getchar();
        while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
        while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
        return x * f;
    }
    
    #define maxn 100010
    #define maxnode 4093490
    #define LL long long
    struct Node {
    	int v, r;
    	LL sum;
    	Node() {}
    	Node(int _, int __): v(_), r(__) {}
    } ns[maxnode];
    int ToT, fa[maxnode], ch[2][maxnode];
    inline void maintain(int o) {
    	ns[o].sum = ns[o].v;
    	for(int i = 0; i < 2; i++) if(ch[i][o])
    		ns[o].sum += ns[ch[i][o]].sum;
    	return ;
    }
    inline void rotate(int u) {
    	int y = fa[u], z = fa[y], l = 0, r = 1;
    	if(z) ch[ch[1][z]==y][z] = u;
    	if(ch[1][y] == u) swap(l, r);
    	fa[u] = z; fa[y] = u; fa[ch[r][u]] = y;
    	ch[l][y] = ch[r][u]; ch[r][u] = y;
    	maintain(y); maintain(u);
    	return ;
    }
    inline void insert(int& o, int v) {
    	if(!o) {
    		ns[o = ++ToT] = Node(v, rand());
    		return maintain(o);
    	}
    	bool d = v > ns[o].v;
    	insert(ch[d][o], v); fa[ch[d][o]] = o;
    	if(ns[ch[d][o]].r > ns[o].r) {
    		int t = ch[d][o];
    		rotate(t); o = t;
    	}
    	return maintain(o);
    }
    inline LL que(int& o, LL v) {
    	if(!o) return 0;
    	LL ls = ch[0][o] ? ns[ch[0][o]].sum : 0;
    	if(v >= ns[o].v) return ls + ns[o].v + que(ch[1][o], v);
    	return que(ch[0][o], v);
    }
    
    int rt[maxn<<2], ql, qr;
    LL V;
    inline void update(int L, int R, int o) {
    	insert(rt[o], V);
    	if(L == R) return ;
    	int M = L + R >> 1, lc = o << 1, rc = lc | 1;
    	if(ql <= M) update(L, M, lc);
    	else update(M+1, R, rc);
    	return ;
    }
    inline LL query(int L, int R, int o) {
    	if(ql <= L && R <= qr) return que(rt[o], V);
    	int M = L + R >> 1, lc = o << 1, rc = lc | 1;
    	LL ans = 0;
    	if(ql <= M) ans += query(L, M, lc);
    	if(qr > M) ans += query(M+1, R, rc);
    	return ans;
    }
    
    int main() {
    	int n = read();
    	for(int i = 1; i <= n; i++) ql = i, V = read(), update(1, n, 1);
    	
    	int q = read();
    	while(q--) {
    		ql = read(); qr = read();
    		LL ans = 0; V = ans + 1;
    		while(1) {
    			LL tmp = query(1, n, 1);
    			if(tmp == ans) break;
    			ans = tmp; V = ans + 1;
    		}
    		printf("%lld
    ", ans + 1);
    	}
    	
    	return 0;
    }
    

    然后 T 飞。T_T

    当然正解是主席树,代码还倍儿短。

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <stack>
    #include <vector>
    #include <queue>
    #include <cstdlib>
    using namespace std;
     
    const int BufferSize = 1 << 16;
    char buffer[BufferSize], *Head, *tail;
    inline char Getchar() {
        if(Head == tail) {
            int l = fread(buffer, 1, BufferSize, stdin);
            tail = (Head = buffer) + l;
        }
        return *Head++;
    }
    int read() {
        int x = 0, f = 1; char c = Getchar();
        while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
        while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
        return x * f;
    }
     
    #define maxn 100010
    #define maxnode 4000010
    int n, m, A[maxn], sum;
     
    int ToT, root[maxn], lc[maxnode], rc[maxnode], sumv[maxnode];
    void update(int& y, int x, int L, int R, int p) {
        sumv[y = ++ToT] = sumv[x] + p;
        if(L == R) return ;
        int M = L + R >> 1; lc[y] = lc[x]; rc[y] = rc[x];
        if(p <= M) update(lc[y], lc[x], L, M, p);
        else update(rc[y], rc[x], M+1, R, p);
        return ;
    }
    int query(int y, int x, int L, int R, int p) {
        if(L == R) return sumv[y] - sumv[x];
        int M = L + R >> 1;
        if(p <= M) return query(lc[y], lc[x], L, M, p);
        return sumv[lc[y]] - sumv[lc[x]] + query(rc[y], rc[x], M+1, R, p);
    }
     
    int main() {
        n = read();
        for(int i = 1; i <= n; i++) A[i] = read(), sum += A[i];
        for(int i = 1; i <= n; i++) update(root[i], root[i-1], 1, sum, A[i]);
        m = read();
        while(m--) {
            int ql = read(), qr = read(), ans = 1;
            int v = query(root[qr], root[ql-1], 1, sum, ans);
            while(v >= ans) ans = v + 1, v = query(root[qr], root[ql-1], 1, sum, ans);
            printf("%d
    ", ans);
        }
         
        return 0;
    }
    
  • 相关阅读:
    ssh 文件传输
    Alipay秘钥问题
    Linux kilin 安装和按键服务器步骤
    常用资源地址
    tomcat虚拟路径
    Dockerfile注意事项
    Ceph部署(二)RGW搭建
    Docker存储驱动之OverlayFS简介
    rdb map出错rbd sysfs write failed
    CEPH-DEPLOY INSTALL时,远端节点在执行APT-GET UPDATE命令时失败
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6202084.html
Copyright © 2011-2022 走看看