• 2021-05 杂题泛做


    Codeforces 1043G

    不难证明出现的答案答案是不大于 (4) 的,否则是 (-1),构造形如:(BACAD)

    直接分开讨论四种答案对应的若干情况

    • (AAAAdots) 的是(lcp)

    • (AAB,BAA) 写一个优秀的拆分,(ABA) 是查 ( m{border})

      考虑这样一个结论:子串存在的长度 (ge sqrt n)(border) 一定满足 (l)(st) 的后缀数组上的排名不超过 (sqrt n)

      证明考虑如果有超过 (sqrt) 个后缀满足在这两个中间,那么其和两端的 ( m{LCP}) 都大于 (sqrt n),明显不存在

    • ( m{ABAC,BACA}) 这个部分直接判是不是两端的字符出现了两次即可

      ( m{BAAC}) 写出来优秀的拆分之后维护 (l_i) 表示从当前点开始最小的位置满足该子串是一个 (AA) 串,是一个 (RMQ)

    四合一挺难受的

    平面最近点对

    记录本题分治做法

    考虑和建立 ( m{KD-Tree}) 的做法类似的,对于当前分治区间 ([l,r]),取 (x) 这维的中位数,递归左右部分,求得两个子集的 (min)

    考虑合并两边的信息不难发现只有 ( m{[Mid_x-min,Mid_x+min]}) 中的点有用

    将区间里面的点按照 (y) 轴归并之后将这些点取出,写一个带朴素剪枝的暴力即可

    考虑这个暴力的正确性:

    对于一个点,可能更新答案的点必然在不大于 ([min imes 2min]) 的一个矩形里面

    将其分割成 (2 imes 3) 的几个小部分,那么每个矩形框里必然不能有超过 (1) 个点,小矩形对角线的长度为 (frac{5}6 min),那么复杂度正确,而且常数不大

    Luogu3322

    关注到是一个深度为 (n) 的线段树的形式,那么这个操作的先后顺序和是不是能翻成一个标准序列无关

    所记录的东西就是操作的次数,并从小向大 ( m{dfs}),最后 ans+=fac[num];

    那么找到所有不是 (+1) 递增的段,如果超过两个一定不合法,剩下的枚举所有情况交换递归

    注意在不合法状态有 (2) 个的情况下,如果得到左 (1) 的解可以不枚举右 (2),通过这样的剪枝得到的复杂度为 (2^{24})

    联通欧拉图计数

    定义是能经过每个边恰好一次并回到出发点的图

    (f_i) 表示有 (n) 个点的欧拉图的数量(不保证联通),因为图的性质(每个点度数都是偶数),那么结果是 (2^{inom {i-1}2})

    设联通欧拉图的数量为 (g_i),枚举 (1) 号点所在的联通块的大小

    [g_i=f_i-sum_{j=1}^{i-1} inom{i-1}{j}f_j g_{i-j} ]

    想要分治 (NTT) 的话好像也不是不行,拆开组合数做即可

    Codeforces986E

    差分询问,运用质数个数少,次数小等和 (gcd) 本质是次数取 (min) 等性质 (dfs) 处理即可

    Codeforces809E

    首先得到这样一个东西:

    [varphi(a_i imes a_j)=frac{varphi(a_i) imes varphi(a_j) imes gcd(a_i,a_j)}{varphi(gcd(a_i,a_j))} ]

    证明直接拿质因子拆就行了,式子变成:

    [ m{frac1{2(n-1)n}sum_{i=1}^nsum_{j=1}^n frac{varphi(a_i) imes varphi(a_j) imes gcd(a_i,a_j)}{varphi(gcd(a_i,a_j))} imes dist(i,j)} ]

    显然枚举 (gcd,) 接着把 (a_i) 扔到其所有因子的 ( m{vector}) 里面,设如下两个函数(没想到吧,竟然是标准的莫比乌斯反演式!)

    [frac1{2(n-1)n}sum_{d=1}^{n} frac{d}{varphi(d)} sum_{i=1}^nsum_{j=1}^n[(a_i,a_j)=d]varphi(a_i)varphi(a_j)dist(i,j) ]

    [f(x)=sum_{i=1}^nsum_{j=1}^n[(a_i,a_j)=x]varphi(a_i)varphi(a_j)dist(i,j)=sum_{d|x}F(d) ]

    [F(x)=sum_{x|d}mu(frac{d}x) f(d)=sum_{x|d}sum_{i=1}^nsum_{j=1}^n[d|(a_i,a_j)]varphi(a_i)varphi(a_j)dist(i,j) ]

    那么把 (dist) 拆开,对每个质因子整个虚树就能得到 (F(d))

    因为要求 (nlog n)(LCA),那么建议使用倍增

    本来还想拆 (varphi=mu * Id) 的,同时学会了简单证明了这个式子

    Codeforces639F

    不难发现题目中要求的就是一个边双,那么先把原图按照边双整成一个森林

    对于每个询问,把边和点的所有集合全拉出来建虚树森林,在上面照样跑边双就行了

    如何写边双?

    inline void tarjan(int x,int pre){
    	dfn[x]=low[x]=++tim;
        for(reg int i=head[x];i;i=e[i].nxt){
        	int t=e[i].to; if(!dfn[t]){
            	tarjan(t,i); low[x]=min(low[x],low[t]);
                if(low[t]>dfn[x]) bridge[i]=bridge[i^1]=1;
           	}else if(i!=(pre^1)) low[x]=min(low[x],dfn[t]);
        } return ;
    }
    

    点双直接判是不是 (dfn[x]le low[t]) 然后弹栈,记割点如下

    if(x!=rt||cvcc>1) cut[x]=1

    其中 ( m{rt})( m{tarjan}) 开始的地方

    Codeforces925E

    有一些显然的思考是把每个点的点权先整成 (-t_i),有变成白点的操作就给链加

    先树剖,然后对树分块,每次修改暴力跳重链按题意模拟即可

    Codeforces896C

    使用珂朵莉树,其本质是使用了数据随机的情况下会有 (frac{1}4) 的概率是区间覆盖操作

    大体就是维护一个里面表示区间的 (set),每个区间的值是相同的

    核心函数就是 assign(),split(),分别表示将区间覆盖和拆开区间,剩下全是直接暴力

    实现上有些新的语法:

    • mutable: 能避开 ( m{set}) 里面的 ( m{const}) 限制

    • erase(iterator_L,iterator_R): 删掉 ( m{set}) 里面 ( m{[L,R)}) 的迭代器

    BZOJ3786

    ( m{Euler Tour Tree}) 用欧拉序(( m{in,out}) 各在序列里面加入一次 )来维护子树

    外层不论套 ( m{splay}) 抑或是 ( m{fhq\_Treap}) 都可以直接对着序列来交换子树

    但是最大的局限性一是维护森林将十分复杂,二是不能换根

    本题树上维护 ( m{tag}) 即可,再附 ( m{fhq\_Treap}) 的写法

    inline int merge(int x,int y){
        if(!x||!y) return x+y; 
        push_down(x); 
        push_down(y); 
        if(rand()%(sz[x]+sz[y])<sz[x]){
        	rs[x]=merge(rs[x],y);
            push_up(x);
            return x;
        }else{
        	ls[y]=merge(x,ls[y]);
            push_up(y);
    		return y;
        }
    }
    inline void split(int rt,int siz,int &x,int &y){
        if(!rt) return x=y=0,void(); 
        if(sz[rt]==siz) return x=rt,y=0,void(); 
        if(!sz[rt]) return x=0,y=rt,void(); 
        push_down(rt); 
        if(sz[ls[rt]]>=siz){
        	split(ls[rt],siz,x,ls[rt]);
            y=rt,fa[x]=0;
        }else{
        	split(rs[rt],siz-sz[ls[rt]]-1,rs[rt],y);
            x=rt,fa[y]=0;
        }return push_up(rt);
    }
    

    Codeforces878C

    不难发现如果两个选手不是所有维度大小性相同,那么都有可能获胜

    所以对于这样的选手缩一把点,维护一个点的个数

    考虑到 (set) 的判等方式是两者的 ( m{operator:<}) 都不成立,那么使用 ( m{set}) 维护一个集合里面的维度最值和集合的大小即可

    答案也就是 “最大” 的集合的大小

    Luogu4426

    考虑树上独立集的求法,暴力 (dp) 可以获得 ( m{10 pts}) 的好成绩

    直接套到图上面不太可取,其实冲突的地方只有非树边 (=m-n+1le 11)

    • 我会二进制枚举!

      (2^{11}) 次方枚举每条边是上侧点选还是下侧点选,剩下的还是一个朴素 (dp)

      值得注意的是可以能有 (E_1) 的下侧点是 (E_2) 的上侧点,所以标记的时候要稍微复杂一点

    • ( m{Key Observation}):有很多的 (dp) 是没有用的,同时如果不在任意一对非树边涉及的点的路径上的点的 (dp) 永远不变

      建立这 (22) 个点的虚树,别的状态的 (dp) 值可以提前预处理出来,剩下的 (dp) 照样二进制枚举做即可

    时间复杂度 (Theta(n+11 imes2^{11}))

  • 相关阅读:
    mybatis(2)操作数据库
    《构建之法》阅读笔记02
    mybatis(4)使用注解方式配置sql语句
    mybatis(5)参数传递
    Android Studio安装
    《构建之法》阅读笔记01
    反射
    mybatis(3)利用Mapper接口实现数据的增删改查
    activity组件
    mybatis(1)
  • 原文地址:https://www.cnblogs.com/yspm/p/14801271.html
Copyright © 2020-2023  润新知