• [蓝桥杯2016初赛]压缩变换


    题目链接:http://oj.ecustacm.cn/problem.php?id=1299

    题目描述

    小明最近在研究压缩算法。他知道,压缩的时候如果能够使得数值很小,就能通过熵编码得到较高的压缩比。然而,要使数值很小是一个挑战。
    最近,小明需要压缩一些正整数的序列,这些序列的特点是,后面出现的数字很大可能是刚出现过不久的数字。对于这种特殊的序列,小明准备对序列做一个变换来减小数字的值。
    变换的过程如下:
    从左到右枚举序列,每枚举到一个数字,如果这个数字没有出现过,刚将数字变换成它的相反数,如果数字出现过,则看它在原序列中最后的一次出现后面(且在当前数前面)出现了几种数字,用这个种类数替换原来的数字。
    比如,序列(a1, a2, a3, a4, a5)=(1, 2, 2, 1, 2)在变换过程为:
    a1: 1未出现过,所以a1变为-1;
    a2: 2未出现过,所以a2变为-2;
    a3: 2出现过,最后一次为原序列的a2,在a2后、a3前有0种数字,所以a3变为0;
    a4: 1出现过,最后一次为原序列的a1,在a1后、a4前有1种数字,所以a4变为1;
    a5: 2出现过,最后一次为原序列的a3,在a3后、a5前有1种数字,所以a5变为1。
    现在,给出原序列,请问,按这种变换规则变换后的序列是什么。

    输入

    输入第一行包含一个整数n,表示序列的长度。第二行包含n个正整数,表示输入序列a。
    1 <=n<=100000,1<=ai<=10^9

    输出

    对于每组测试数据,输出一行,包含n个数,表示变换后的序列。

    样例输入 Copy

    5
    1 2 2 1 2
    

    样例输出 Copy

    -1 -2 0 1 1

    思路:

    因为数字的范围的大小是 [1,1e9] 所以不会考虑用数组去记录下标,那么干脆就采取 map 去记录下标

    然后要求 [l,r] 之间数字的种类的个数 ,因为是区间问题 ,所以就采取线段树去维护区间

    如果一个数字是第一次出现,那么它的这个位置 +1  如果它是第二次(或以上)出现,那么它之前的位置需要 -1  (有点像前缀和)

    #include <iostream>
    #include <algorithm>
    #include <string>
    #include <string.h>
    #include <vector>
    #include <map>
    #include <stack>
    #include <set>
    #include <queue>
    #include <math.h>
    #include <cstdio>
    #include <iomanip>
    #include <time.h>
     
    #define LL long long
    #define INF 0x3f3f3f3f
    #define ls nod<<1
    #define rs (nod<<1)+1
     
    const int maxn = 1e5 + 10 ;
    const LL mod = 20010905;
     
    struct segment_tree {
        int l,r;
        int val;
        int lazy;
    }tree[maxn << 2];
     
    void pushup(int nod) {
        tree[nod].val = (tree[ls].val + tree[rs].val);
    }
     
    void pushdown(int nod) {
        tree[ls].lazy += tree[nod].lazy;
        tree[rs].lazy += tree[nod].lazy;
        tree[ls].val += (tree[ls].r-tree[ls].l+1) * tree[nod].lazy;
        tree[rs].val += (tree[rs].r-tree[rs].l+1) * tree[nod].lazy;
        tree[nod].lazy = 0;
    }
     
    void build(int l,int r,int nod) {
        tree[nod].l = l;
        tree[nod].r = r;
        if (l == r) {
            tree[nod].lazy = 0;
            tree[nod].val = 0;
            return ;
        }
        int mid = (l + r) >> 1;
        build(l,mid,ls);
        build(mid+1,r,rs);
        pushup(nod);
    }
     
    void modify(int x,int y,int z,int k=1) {
        int l = tree[k].l,r = tree[k].r;
        if (x <= l && y >= r) {
            tree[k].lazy += z;
            tree[k].val += (r-l+1) * z;
            return ;
        }
        if (tree[k].lazy)
            pushdown(k);
        int mid = (l + r) >> 1;
        if (x <= mid)
            modify(x,y,z,k<<1);
        if (y > mid)
            modify(x,y,z,(k<<1)+1);
        pushup(k);
    }
     
    int query(int x,int y,int k=1) {
        int l = tree[k].l,r = tree[k].r;
        if (x <= l && y >= r)
            return tree[k].val;
        if (tree[k].lazy)
            pushdown(k);
        int mid = (l + r) >> 1;
        int sum = 0;
        if (x <= mid)
            sum += query(x,y,k<<1);
        if (y > mid)
            sum += query(x,y,(k<<1)+1);
        return sum;
    }
     
    int a[maxn];
    std::map<int,int> mp;
     
    int main() {
        int n;
        scanf("%d",&n);
        build(1,n,1);
        for (int i = 1;i <= n;i++) {
            int v;
            scanf("%d", &v);
            if (mp.count(v)) {
                int pre = mp[v];
                a[i] = query(pre+1,i);
                modify(pre,pre,-1);
            }
            else {
                a[i] = -v;
            }
            mp[v] = i;
            modify(i,i,1);
        }
        for (int i = 1;i <= n;i++)
            printf("%d ",a[i]);
        return 0;
    }
  • 相关阅读:
    一对一关联
    一对多关联
    软删除
    分层控制器
    系统的助手函数
    tp5命令行基础介绍
    PHP 开启跨域
    生成数据库模型文件
    REST API 安全设计指南
    jquery-Ajax请求用例码
  • 原文地址:https://www.cnblogs.com/-Ackerman/p/12245097.html
Copyright © 2020-2023  润新知