• 模拟测试20191026


    $T1:666$

    开始以为是数学

    打了个表发现步数不超过$50$

    直接模拟就好了诶

    枚举步数,每次扫所有点尽量往后走就好了

     

    $T2:123567$

    考场$40pts$后就失去梦想了啊

    正解是大神杜教筛(%%%大神$DeepinC$

    先看$40pts$的柿子

    $$sum_{i=1}^{sqrt n}mu_{i} imes frac{n}{i imes i}$$

    看后边这个$frac{n}{i imes i}$,是不是和某些东西有点像?

    没错,除法分块!

    可以发现$1e18$在这样的除法分块下只有约$188$万种取值

    $mu$ 可以直接杜教筛求前缀和

    1 for(ll i=1,j;i*i<=n;i=j+1){
    2     j=sqrt(n/(n/i/i));
    3     ans+=(n/i/i)*(S(j)-S(i-1));
    4 }
    除法分块

    T3:椎

    考场$YY$一棵$Treap$然而暴毙了

    正解线段树维护单调栈

    我们考虑大根堆$Treap$的结构

    1,如果把所有点按照$key$排序的话,他们的$lca$就是他们之间$val$最大的点

    2,一个点$i$的深度就是 $从左维护单调栈到i时栈内数的个数+从右开始维护单调栈到i时栈内数的个数-1$

    用线段树维护单调栈就可以了

    怎么维护?

    考虑$solve(l,r,v)$表示把$v$放入区间$[l,r]$的单调栈内后的单调栈

    既然是线段树,那主要难点在于怎么合并两个区间

    现在我们以左边为例分两种情况考虑

    $1,[l,r]subseteq 当前查询区间$

    (1) 插入值$geq$右区间最大值

      直接递归查询左边,即调用$solve(l,mid,v)$,因为右边一定都被弹出

    (2) 插入值$<$右区间最大值

      先递归查询右边,即调用$solve(mid+1,r,v)$,然后把右边最大值插入并递归查询左边,即调用$solve(l,mid,max_{rc})$

      后面的操作维护的就是把右边插入左边后左边剩余个数

    $2,[l,r]cap 当前查询区间$

    优先查询右边,即调用$solve(mid+1,r,v)$,同时用一个全局变量维护已经查询过的区间的最大值$lst$_$max$

    然后如果$[l,mid]cap 当前查询区间$ 把现在这个最大值扔到左区间查询,即调用$solve(l,mid,lst$_$max)$

    最后就得到了$solve(l,r,v)$

    但是这样复杂度不对,因为情况1有可能扫了整个被查询区间,复杂度退化成了$O(n^{2})$

    然而我们发现1(2)情况中调用的$solve(l,mid,max_{rc})$和v无关

    那么我们可以在插入一个数时把这玩意预处理出来

    复杂度$O(nlog^{2}n)$

  • 相关阅读:
    RequireJS进阶(二)
    JavaScript判断元素为数字的奇异写法
    RequireJS进阶(三)
    RequireJS进阶(一)
    读Ext之十四(Ext元素)
    JavaScript中__proto__与prototype的关系
    工作流术语
    一个例子(Hello World)
    无题
    再谈调用子流程(1)
  • 原文地址:https://www.cnblogs.com/mikufun-hzoi-cpp/p/11746698.html
Copyright © 2020-2023  润新知