• 奇技淫巧


    0.如果不是秒切的话,解决问题的一般思路:

    1.退而求其次:如果数据小、没有某个限制怎么办?(可以通过暴力分得到提示)

    2.找到矛盾问题的根源,就是算法升级的关键,如果有了这个限制,怎么处理?

    3.集中处理这个矛盾

    本篇博文记录一些机智操作,简洁方法,奇技淫巧。

    1.快读:

    void read(int &x)
    {
        char ch;bool flag=false;
        while(!isdigit(ch=getchar()))
            (ch=='-')&&(flag=true); 
        for(x=num;isdigit(ch=getchar());x=x*10+num);
         (flag)&&(x=-x);
    }

    注意:&x和&&前后两个的顺序

    支持:整形读入。包括负数

    2.取模优化:

    inline int mod(int x)
    {
        return x-p*(x/p);
    }

    3.线段树define操作

    struct node{
        int l,r;
        int add,ch;
        int mx,hx;
        int had,hch;//一段时间内最值  
        #define ad(x) t[x].add
        #define ch(x) t[x].ch
        #define mx(x) t[x].mx
        #define hx(x) t[x].hx
        #define ha(x) t[x].had
        #define hc(x) t[x].hch
        #define l(x) t[x].l
        #define r(x) t[x].r
    }t[4*N];

    摘自:cpu监控

    4.define int long long

    适用于无脑调试

    但是空间极其紧张,除非没时间改,否则不要用这个。

    5.num[++num[0]]=x;

    用num[0]计数,有多个数组的时候,不会弄混cnt名称

    6.fix

    当数组中可能遇见负数的时候,可以考虑采用修正值fix,将取值的区域平移。

    如:NOIP2016 D1T2 天天爱跑步, 处理d[si]-2*d[lca]<0 , w[x]-d[x]<0时,取值范围在:[-n,n]

    直接再加上n,平移到[0,n]就可以直接处理了。

    7.区间中位数

    二分一个中位数的值ans,大于ans的赋为1,小于-1(等于再说)

    找区间内有无连续子段和大于0,判断ans+还是ans-

    8.字符读入避免空格

    ztb法:char s[] scanf("%s",s+1) 利用字符串自动剔除前面空格,并且读到下一个空格位置。

    chen_zhe法:char c scanf("%s",&c) 敢情这也可以。。。。

    9.Hungary匈牙利算法每次memset的小优化(默认左部点出发dfs)

    ①一般情况下,我们是每次找到一个右部点,vis[y]=1,之后每次memset一下vis

    ②但是,有的时候,右部点很多,memset一下,nleft*nright 就挂了。

    而如果左部点很少,可以尝试标记左部点的vis,

    因为,我们之所以标记vis,是因为,不能在dfs(pre[y])时,从pre[y]里不断返回pre[y]自己(考虑代码模拟一下)。

    如果标记左部点,那么,回到自己时,会因为已经vis,直接返回0

    换句话说,①方案是不让你找到y,而②方案,是回到自己再打断。本质一样。

    ③我们也可以用一个栈sta[],收集右部点vis的点,用弹栈并归零处理vis。

    为什么复杂度在②条件下没问题??

    其实,最坏和②复杂度是一样的,一般情况下更优。

    因为,我们每找到一个!vis[y],就要做出选择,要么!pre[y] 返回true,要么dfs(pre[y])

    返回就返回了,打断搜索。如果dfs下去,那么必然要到了一个新的左部点。

    所以,每vis一个,最多多访问一个左部点。所以,sta[]中元素的数量和左部点数量是一致的。

    所以,最坏情况下,和②是一样的。

    (2018.9.8  update:其实根本可以不用每次尝试清空什么vis!!!

    我们可以采用时间戳的东西,vis[i]变成int数组,表示最后一次访问这个右部点的左部点的编号!

    如果这一次的没有访问i,即vis[i]!=id  那么就令vis[i]=id,就不用每次清空了!

      

    int vis[N],pre[N];
    int id;
    bool dfs(int x){
        for(int i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(vis[y]!=id){
                vis[y]=id;
                if(!pre[y]||dfs(pre[y])){
                    pre[y]=x;
                    return true;
                }
            }
        }
        return false;
    } 
    for(int i=1;i<=mx;i++){
        id++;
        if(dfs(i)) ans++;
    }

    10.多个点的lca

    dfs序最小点和dfs序最大点取lca即可。

    因为dfs总是先搜完一个子树,又因为两个点遍历时间相差最远。画图理解一下。

    类似:JZ模拟赛 8.9 B组T3

     

    11.区间维护最小值,支持删除,插入

    1.multiset

    2.差的最小值呢?两个set,第二个set维护数值set相邻两个的差值。插入删除用前驱后继处理。

    详见:JZ模拟赛 8.9 A组T3

    12.双哈希

    有的时候,出题人要卡你。一个哈希值可能出现的差错是:

    本来不同的两个串,通过取模运算,就可能相同了。

    所以,我们通过两个串,如果两个有一个哈希值不同,就认为串不同了。

    否则,认为串相同。

    注意,不可能出现相同的串哈希值不同的情况,因为算法一样,得到的哈希值一定相同。

    13.曼哈顿距离转切比雪夫距离

     (x,y) -> (x-y,x+y)重新设置点的坐标。

    (x1,y1),(x2,y2) -> (x1+y1,x1-y1), (x2+y2,x2-y2)

    分类讨论可以证明:|x1-x2|+|y1-y2|=max(|x1-x2|,|y1-y2|)

    这样,就可以把一个加法变成最值问题。

    可以处理曼哈顿距离最小生成树。

    用两个set一个维护没有加入当前点集中的点,横坐标,纵坐标。

    用四个数维护当前点集最小x,最大x,最小y,最大y

    每次从set找四个点和最小x,最大x,最小y,最大y找最小距离加进去。

    因为,只要从x找一个max,y找一个max,再取max就可以。

    14.变进制数存储状态,状压dp

    变进制法不错的讲解:NKOJ1633 神仙开山【变进制数状压DP】

    还有一个应用:JZ模拟赛 8.18   A组T3

    就是,根据每个数的出现次数不同,每个数位置的进制都不同。

    这样,可以达到压缩状态数到最小的结果。

    15.一点反演技巧

    (i,j)=1 时,等价于:∑d d|i&&d|j u(d) =1

    (i,j)!=1时,等价于:∑d d|i&&d|j u(d) =0

    即通过判断i,j所有公约数的u的和是否为1,判断i,j是否互质。

    证明:

    i,j互质的时候,公约数只有1,u(1)=1

    i,j不互质的时候,公约数就是i,j最大公约数的约数。

    设gcd(i,j)=p1^q1*p2^q2*...pk^qk

    那么,如果取两个以上的pi,u就是0,不影响答案。

    所以,就是取p1、。。。pk一个或不取的方案数要考虑

    取零个:C(k,0)个1

    取一个 :C(k,1)个-1

    取两个 :C(k,2)个1

    。。。

    所以,最后的答案是:C(k,0)-C(k,1)+C(k,2)-C(k,3)+...+C(k,k)

    根据组合数的性质,不论k是奇数还是偶数,答案都是0

    证毕。

    16数学期望dp小结

    总结:

    数学期望以难以证明的性质,花样繁出的特点闻名于OI界。

    其难以下手的恐惧,令不少蒟蒻心有余而力不足。

    还是抓住关键的线性递推式,和期望定义 。 慢慢仔细分析。

    对于期望状态的设计:

    1.多个终点一个起点,就f[i]表示,从i到终点的期望步数,f[s]即为答案

    2.多个起点一个终点,就f[i]表示,从起点到i的期望步数,f[t]即为答案

    3.与终点无关的树形期望dp,通常往子树对i,父亲对i影响考虑,和一般的树形dp类似。

    17.曼哈顿距离和切比雪夫距离转化

     

    18.gets()读入整行字符串,然后再 处理。

    或者getchar()读入空格换行,scanf("%s")读入单词等

    19.扩展欧拉定理:

    $b^cspace mod p=b^{cspace mod p+phi(p)}mod p (c>phi(p))$

    p,b可以不互质

    20.计算三角形面积。

    坐标:(x1,y1),(x2,y2),(x3,y3)

    把(x3,y3)移动到原点。得到新的(x1,y1),(x2,y2)

    S=|x1y2-x2y1|/2

    可以避免精度误差

    21.二分图带权最大匹配

    如果左部点只连接两个边,可以认为是两个右部点之间连接了一条边。

    形成了一个无向图(可能不连通),相当于给边定向。

     

     22.无理数的高精度处理

    (适用于($(a+b imessqrt{x})^k$):

    1.保留“a+b*根号”的形式:构造有序数对:(a,b),即可定义乘法。

    2.精度问题:令

    无理项消除,N是整数。如果$(a-b imessqrt{x})^k)$小于1的话,k比较大,就逼近0,k比较小,double可以承受。

    例题:圆——高精无理数的处理

    23.快速质因数分解:

    如果要多次询问在1e7范围内的质因数分解,可以利用线性筛预处理每个数的最小质因子,然后不断除以mindiv,即可在低于logn时间下完成分解。

    而且质因子已经自动排好序了。

    例题:CF757E Bash Plays with Functions

    24.十进制快速幂(专治高精快速幂)

    和二进制快速幂原理一样。

    y要循环$log_{10} y$次。

    每次x要左移一位,相当于一个快速幂$log_2 {10} $次。

    所以,总的复杂度其实也是:$log_{10} y imes log_2 {10} = log_{2} y$

    但是,当y是一个高精度的时候,如果用十进制储存,每次/2是O(长度)的,会TLE。

    然而十进制快速幂直接舍弃最后一位,可以O(1)进行移位。

    (由于复杂度在低精度下是一样的,所以除了高精快速幂,并没有什么卵用)

    25.爆栈的处理方法

    26.HASH判断循环节

    对于O(1)判断si是sj的循环节:

    hash(sj)*p^leni+hash(si)=hash(si)*p^lenj+hash(sj)

    证明方法类似kmp的循环节证明。

    27.C(n,m)奇偶性

    结论:C(n,m)为奇数,当且仅当n&m=m,即m是n的子集。

    证明:

    根据LUCAS定理,C(n,m)=1 mod 2 意味着,n,m二进制上的每一位,都有n是1,m是0,或者n是1,m是1.或者n是0,m是0.

    如果n是0,m是1的话,那么C(0,1)=0,那么就是0了。

    28.所有取值的前k最值问题

    考虑每个可能的决策点是否有贡献。

    1.起初把每个点的最优解找出来,带着点的id,放进堆里面。

    2.从堆里取出最优解。

    3.把和这个id有关的次优解找出来,放进堆里。

    重复2、3

    适用于一些有固定可能存在的决策点。并且能够快速找到和这个点有关的第k优的值。

    例题:BZOJ3689: 异或之

    [NOI2010]超级钢琴

    29.转化研究对象:

    枚举每个决策点,计算决策点包含的物品的贡献——>枚举物品,计算对能产生影响的决策点的贡献。

    后者,用于计数,就是分开考虑每个元素。对于最值决策,计算之后直接对决策点取最值。

    30.-Wall -W

    工具——编译选项——编辑器——编辑时加入以下命令:-W -Wall

    小错可以警告

    #pragma GCC ("-W1,--stack=128000000)手动开栈。

     

     31.对于一些序列两次取值的问题(两次取值位置不相交)

    可以正着dp,f[i],前i个位置选择一个

    再反着dp,g[i]i~n位置选择一个。

    然后枚举分界点,即可。

    ans=max(ans,f[i]+g[i])

    32.雪球数:

    一个数的所有非空前缀组成的数都是素数。

    例如:313 :3,31,313都是素数。

    然而,雪球数有最大的数并不是无限的:73939133

    33.NOI Linux编译

    1.进入Linux虚拟机

    2.桌面新建文件。打开。

    3.复制代码进去。

    4.重命名为my.cpp(后缀为cpp)

    5.Ctrl+Alt+T 进入终端

    6.输入cd Desktop进入桌面界面(忘了文件名,输入ls Desktop 显示桌面的所有文件)

    7.输入g++ my.cpp -o my.exe

    (有需要的话,后面加上-std=c++11 -Wall -O2)

    8.如果回车之后,没有其他信息(没有error),那么编译成功。

    9.接下来输入./my.exe (注意之间没有空格)表示进入这个exe

    然后类似windows下的cmd,直接输入数据即可。

     (按动↑可以寻找上面进行过的命令)

    34.半平面交atan2

    排序时,求向量旋转角的时候,用atan2(y,x)比较好

    既可以保证精度,而且范围是在(-Pi,Pi]的。可以表示所有的旋转角。而且,如果atan2(t,0)的话(t>0),会返回Pi/2,

    并不会因为tan(Pi/2)不存在而RE等。

    35.int a=floor((double)b+0.5)

    适用于:FFT等需要四舍五入以及处理-0.0的情况。
    (注意,负数的时候,强转int是向中取整,floor是向下取整,有所不同。看情况决定)

    而且,FFT最后输出的时候,

    for(reg i=0;i<=m;++i){
            b[i].x/=n;
            int pp=b[i].x+0.5;
            printf("%d ",pp);
        }

    代替

    for(reg i=0;i<=m;++i){
            b[i].x/=n;
            printf("%.0lf ",fabs(b[i].x));
        }

    可以快一倍!

     还有一个东西叫round(x)

    (int)y=round((double)x)

    四舍五入函数。

    36.FFT三次变两次:

    就是把P(x)=F(x)+G(x)i

    P(x)^2虚数部分/2即可。节省一次DFT

    傅里叶变换(FFT)学习笔记

    37.O(1)求LCA

    用欧拉遍历序遍历树,然后RMQ记录深度。LCA就是之间深度最浅的,O(1)查询

    详见:LCA 最近公共祖先

    38.堆优化dij的一个小剪枝

    1.不必每次把所有的出边更新到的都加入到堆里

    类似spfa,如果dis[y]>dis[x]+e[i].val那么dis[y]=dis[x]+e[i].val,q.push(po(y,dis[y]))

    这样常数会小一些。多次dij,优化就明显了。

    2.还可以用num记录已经确定的点的个数,如果num=0直接return

    适当减少了常数(但是如果要多次dij的话,别忘了清空堆)

    39.关于平均值的二分

    上面有中位数的二分,平均值也可以二分

    每个数减去平均值,如果区间和大于等于0,那么可以

    fzyzojP1635 -- 平均值

    40.一个前缀问题

    一个有向图,S到T经过至少k条边的最短路,这个要T自己和自己连个自环,表示保留下来

    2.11考试

    41.关心应该关心的

    缩减冗余状态:各种DP中用到

    合并类似转移及状态:数组平移,维护分段函数,20190211 模拟训练 A. 大猫咪

    修改之间忽视并不会变的:虚树、动态DP

    42.异或下线性方程组的自由元个数:

    先变成n*(n+1)的矩阵

    然后高斯消元,如果某一个id找不到,那么一定是自由元了,计数器++

    注意,每次找i和消除必须在全局位置,并且用一个vis标记表示是否还能动(因为有时候存在自由元X_i,但是第i行其实还能用)

    最后削成的上三角矩阵,除了无解情况,剩下的一定有唯一解

    (一般的线性方程组也是这样求,只不过xor下的自由元用的比较多)

    代码见:bzoj4671: 异或图——斯特林反演

    43.一个通用技巧是:

    一个通用技巧是:

    找到两个数组f,g

    f范围宽松好统计,g范围严格难统计但是和答案有直接关系,

    这样,只要得到f和g的关系,就可以找到答案!

    经常是可以得到f由g的表达式,然后斯特林反演或者二项式反演得到g的求法

    也可以用多项式科技

    数论函数的反演也可以这么做。

    luoguP4841 城市规划

    bzoj4671: 异或图——斯特林反演

    已经没有什么好害怕的了——二项式反演+经典套路

    44.枚举LCP

    一些对于字典序大小,或者二进制下有大小比较限制的按位操作的题

    枚举LCP可以有效体现比较大小的“实质”

    一般外层枚举LCP,内层用DP处理方案。

    来自多校的一个题——数位DP+卡位

    45.O(n^2)插值

    [学习笔记]拉格朗日插值

    46.一种生成函数还原序列的方法

    有时候,两个生成函数卷积起来,要展开以后求x^k的系数,但是k很大。

    ①如果一个生成函数的次方的话,就是组合意义小球放盒子了,O(1)有公式,LUCAS求组合数

    ②否则考虑能不能把其中一个的生成函数变成有限项,使得项数在O(n)以内

    例如:自古枪兵幸运E

    47.给DAG转移重新定向

    可以做到O(sqrt(m))的出边个数。支持暴力枚举Day5

    48.树剖维护子树&&连通块信息

    PK LCT

    基于动态DP的思想,记录往轻儿子的贡献。重儿子现场计算。Day5

    便于打标记。便于写。(毕竟是静态树)

    49.取Ln

    1.有标号图计数,F表示所有情况,G表示连通情况。则:G=Ln(F)

    反之,F=exp(G)

    证明可以参考:

    luoguP4841 城市规划

    COGS 2353 2355 2356 2358 有标号的DAG计数

    2.把乘法变成加法,

    ①多项式降次

    付公主的背包

    luoguP4705 玩游戏

    ②把答案大的变小,仍然满足单调性,所以取最小值方案还是不变的。

    [BJOI2019]奥术神杖 取Ln直接就变成0/1分数规划了

    3.碰见Ln(f)很麻烦?

    求导就把f搞出来了。

    4.求积分时候,处理分式分母

    待定系数法。1/(ax+b)->Ln(|ax+b|)直接加上绝对值,求导回去还是成立的

    50.分母没有逆元

    前提是求一个分子分母都是连乘积的分式

    可以考虑表示成:x*p^y的pair形式,最后上下把p的次数相减(类似扩展Lucas)

    具体操作:(a,b)*(c,d)=(a*c,b+d)

    然后检查(a,b):如果a%mod==0,(a,b)->(a/mod,b+1),否则(a,b)->(a%mod,b)

    显然这样取模,mod的次数不会减少。

    51.DINIC从T开始BFS常数更小

    显然DINIC的瓶颈在于增广。

    所以一些必然不会到达T的点就不用访问了。

    所以从T开始搜分层图。

    虽然一些点S不能到达,但是浪费的只是BFS的常数,反之浪费的就是增广时候的常数了。

    52.

    53.真·奇技淫巧

    O(p)预处理,O(1)任意底数,任意质数的快速幂

    $a^b=G^{log_G{a^b}}=G^{b imes log_Ga}$

    然后$log_Ga$对于所有的$a in [0,p-1]$可以预处理

    对于$G^{x}$可以直接预处理

     54.树上点集到点集的最大值

    边权为正数

    一个常用的套路:一个树上点集的直径,可以直接合并两个集合得到。四个端点C(4,2)计算即可。

    猫的某个随机连通块直径题、安师大的某个O(n^4)预处理二分+前缀和查询、51nod1766

    55.编号区间点集,信息可以合并?

    一个常用套路:编号区间?线段树!线段树区间维护这个区间的信息即可

    Max Mex 51nod1766

    56.不能立刻决定球的颜色?

    每个球的颜色个数固定,不能放一个球就染色

    可以先认为是白色,然后某一个时刻钦定k个白色成为某一个颜色。只要知道之前有多少个白色就可以了。

    UOJ#449. 【集训队作业2018】喂鸽子

    57.IDFT的trick

    如果遇到矩阵乘法套多项式,最后就求一个多项式的系数的话,可以考虑用IDFT的trick降低常数

    具体是:直接把转移矩阵的x换成$w_N^i$,得到$Ans(w_N^i)$最后再插值。

    一个乘法的常数,比卷积的常数小太多了。

    UOJ#424. 【集训队作业2018】count

    58.__builtin

    59.树上后缀排序

    有的时候很有用。比EXSAM好写好调。

    60.Cnt(S,T)

    表示起点在S,终点在T集合的边的条数

    不能预处理,O(n)也有点慢。

    可以bitset!处理S集合的出边包括哪些编号,T集合的入边包括哪些编号,求&

    61.bitset与字符串匹配?

    [国家集训队]JZPSTR

    字符集很小的时候,可以对每个字符集维护出现位置。

    各种插入删除可以手写bitset进行。

    xi=x%Mi+1Mi

    2.

  • 相关阅读:
    Android 主题theme说明 摘记
    Android开发 去掉标题栏方法 摘记
    安卓项目五子棋代码详解(二)
    关于 ake sure class name exists, is public, and has an empty constructor that is public
    百度地图3.0实现图文并茂的覆盖物
    android onSaveInstanceState()及其配对方法。
    关于集成科大讯飞语音识别的 一个问题总结
    android 关于 webview 控制其它view的显示 以及更改view数据失败的问题总结
    C# 解析 json Newtonsoft果然强大,代码写的真好
    c#数据类型 与sql的对应关系 以及 取值范围
  • 原文地址:https://www.cnblogs.com/Miracevin/p/9031419.html
Copyright © 2020-2023  润新知