codeforce 285 div2 D 题解

codeforce 285 div2 D 题解

说明

这道题目是看了思路分析才知道的,关键问题在于数据量过大,需要快速检索的同时不能辅助空间过大.

因此利用了下面3种方法结合解决该问题

  • 康拓展开与逆康拓展开
  • 树状数组
  • 二分查找

代码

/**
 * @brief Codeforces Round #285 (Div. 2) d
 * @file d.cpp
 * @author mianma
 * @created 2015/01/27 18:18
 * @edited  2015/01/29 22:45
 * @type math tree
 */
#include <fstream>
#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <map>
#include <vector>
#include <set>
#include <utility>
#include <stack>

using namespace std;

#define max(a, b)  ((a) > (b) ? (a) : (b))
#define min(a, b)  ((a) > (b) ? (b) : (a))
#define abs(a)     ((a) >  0  ? (a) : (0 - (a)))
#define CLR(vec)   memset(vec, 0, sizeof(vec))
#define PI         acos(-1.0)

#ifdef DEBUG
ifstream in;
ofstream out;
#define CIN in
#define COUT out
#else
#define CIN cin
#define COUT cout
#endif

/*api for binary index tree*/
static inline int low_bit(int i){
    return ( i & ( - i));
}

static inline void build_bit(int *vec, int *bit, int size){
    for(int i = 1; i <= size; i++){
            bit[i] = vec[i];
            for(int j = i - 1; j > i - low_bit(i); j-= low_bit(j))
                bit[i] += bit[j];
    }
}

static inline int sum_bit(int *bit, int k){
    int ans = 0;
    for(int i = k; i > 0; i -= low_bit(i))
        ans += bit[i];
    return ans;
}

static inline void update_bit(int *bit, int size, int i, int val){
    for(int j = i; j <= size; j += low_bit(j))
            bit[j] += val;

}

/* O(lgn) search, O(lgn) update , O(n) memory cost*/

static inline void debug_vec(int *vec, int size){
    for(int i = 0; i < size; i++)
        COUT << vec[i] << " ";
    COUT << "
";
}

#define MAXN 200010

int n;
int p[MAXN];
int q[MAXN];
int bit[MAXN];

int main(void){
    ios_base::sync_with_stdio(0);
#ifdef DEBUG
    CIN.open("./in",  ios::in);
    COUT.open("./out",  ios::out);
#endif

    /* Cantor expansion */
    CIN >> n;
    int tmp;
    CLR(bit);
    for(int i = 1; i <= n; i++){
        CIN >> tmp;
        tmp++;
        update_bit(bit, n, tmp, 1);
        p[i] = tmp - sum_bit(bit, tmp);
    }

#ifdef DEBUG
    COUT << "vec for p
";
    debug_vec(p + 1, n);
#endif

    CLR(bit);
    for(int i = 1; i <= n; i++){
        CIN >> tmp;
        tmp++;
        update_bit(bit, n, tmp, 1);
        q[i] = tmp - sum_bit(bit, tmp);
    }

#ifdef DEBUG
    COUT << "vec for q
";
    debug_vec(q + 1, n);
#endif

    for(int i = n; i >= 1; i--){
        p[i] += q[i];
        p[i - 1] += p[i]/(n - i + 1);
        p[i] = p[i]%(n - i + 1);
    }

#ifdef DEBUG
    COUT << "vec for p + q
";
    debug_vec(p + 1, n);
    COUT << endl;
#endif

    /*record nums not used*/
    CLR(bit);
    for(int i = 1; i <= n; i++)
        update_bit(bit, n, i, 1);

    /* reverse Cantor expansion */
    for(int i = 1; i <= n; i++){
        int val = p[i] + 1;
        int lft = val;
        int rht = n;

        /*binary search*/
        while(lft < rht){
            int mid = ( (rht - lft)>> 1) + lft;
            int top = sum_bit(bit, mid);
            if(top < val){
                lft = mid + 1;
            }else{
                rht = mid;
            }
        }
        q[i] = lft;
        update_bit(bit, n, lft, -1);
    }

    for(int i = 1; i <= n; i++)
        COUT << q[i] - 1 << (i == n ? "
" : " ");
    return 0;
}
时间: 2024-12-26 03:22:06

codeforce 285 div2 D 题解的相关文章

codechef MAY18 div2 部分题解

T1 https://www.codechef.com/MAY18B/problems/RD19 刚开始zz了,其实很简单. 删除一个数不会使gcd变小,于是就只有0/1两种情况 T2 https://www.codechef.com/MAY18B/problems/XORAGN 我们可以把B序列看做一个矩阵 那么$A(i,j)$和$A(j,i)$会抵消掉 因此答案就是$\sum_1^n A(i,i) + A(i,i)$ T3 https://www.codechef.com/MAY18B/pr

codeforce #633 div2

A. Filling Diamonds # 题意 给定一个初始的菱形,给定一个n,用这个菱形去覆盖给定n对应的图形,不同的覆盖即同一个小形状被两个不同的菱形覆盖 # 题解 发现当一个竖着的被填充后其余的都是斜横着的,所以只需要找竖着的情况,显然等于n 1 #include <bits/stdc++.h> 2 using namespace std; 3 void work(){ 4 int n; 5 cin>>n; 6 cout<<n<<endl; 7 }

codeforce 382 div2 E —— 树状dp

题意:给一棵n个结点的无根树染色,求使每个结点距离为k的范围内至少有一个被染色的结点的总染色方法数目 分析:首先我们定义: 对于结点v, 如果存在一个黑色结点u距离v不超过k,则结点v被"控制" 首先将无根树转换成以1为根的有根树,设dp[v][i]为对于以v为根的子树,距离v最近的黑色结点深度为i时, 该子树中结点全部被控制或者可能在其他子树的影响下被全部控制的染色方法数. 下面来解释一下, 我们知道,当两个黑色结点距离不超过2*k+1时,其间的所有节点都被控制.那么当 i <

codeforce 310 div2 D题 Case of Fugitive

题目 给n个岛屿和m座桥,问桥是否足够把两两相邻的岛屿连起来,当一座桥的长度大于等于相邻两个岛屿上的点的距离最小值并且小于等于相邻两个岛屿上的点的距离最大值的时候,就可以把他们连起来. 用贪心的方法,把岛屿按照距离的最小值(即l[i+1]-r[i])排序,把桥按照长度排序,显然距离最小的岛屿应该用长度最小的桥来接,这是第一个贪心.第二个贪心是当前岛屿可以连接的所有桥中应该选距离最大值最小的.仔细想想这两个贪心思路是对的.最后看是否所有的岛屿都被连起来就行了. 代码: #include <cstd

codeforces #593 div2 ABCD 题解

A. Stones Description 给出3堆物品,个数分别为a,b,c 有两种取数方式,a1b2,b1c2,问最多取多少物品 Solution $O(n^2)暴力$ 1 #include <algorithm> 2 #include <cctype> 3 #include <cmath> 4 #include <cstdio> 5 #include <cstdlib> 6 #include <cstring> 7 #inclu

Codeforces #275 div2

链接:codeforce #275 div2 A.Counterexample 题意:给定左右区间[l,r],求区间内的三个数a,b,c使得a与b互质, b与c互质,但a与c不互质,若不存在,输出-1 分析:找连续的偶奇偶序列即可 #include<stdio.h> int main() { __int64 l,r; scanf("%I64d%I64d",&l,&r); if(l%2) l++; if(r-l<2) printf("-1\n&

Codeforces Round #479 (Div. 3) 题解

Codeforce官方给的题解 传送门 A. Wrong Subtraction 交题的传送门:http://codeforces.com/contest/977/problem/A 题意:题意很简单,就是给你一个数,如果能够整除10就直接将该数缩小10倍:否则直接将这个数减一.问k此操作之后,这个数n变为多少? 题解:直接按照题意模拟即可QAQ 代码如下: 1 //A 2 #include<bits/stdc++.h> 3 using namespace std; 4 5 int main(

contest3 CF994 div2 ooxxx? oooox? ooooo?

题意 div2 C (x)(o) 在一个平面上, 给一个水平的正方形和一个\(45^.斜\)的正方形 求是否相交(共点也算), 坐标正负\(100\)以内 div2 D (x)(o) \(A,B\)两个人初始分别被给了一个数对, 其中有且仅有一个数相同(\([1,9]\)下同) 接下来\(A,B\)分别展示\(n,m\)个数对(\(\le 10\)个),其中包含他们初始拿到的 现在你作为观察者 若能推出初始数对中相同的是哪个数, 输出他 若\(A,B\)两个人都能推出, 但你不知道, 输出\(0

【算法30】从数组中选择k组长度为m的子数组,要求其和最小

原题链接:codeforce 267 Div2 C 问题描述: 给定长度为n的数组a[],从中选择k个长度为m的子数组,要求和最大. 形式描述为:选择$k$个子数组[$l_1$, $r_1$], [$l_2$, $r_2$], ..., [$l_k$l1, $r_k$] (1 ≤ $l_1$ ≤$r_1$ ≤$l_2$ ≤ $r_2$ ≤... ≤$l_k$ ≤ $r_k$ ≤ n; $r_i-r_i+1$), 使得$\sum_{i=1}^{k}\sum_{j=l_i}^{r_i}p_j$ 问题