zoukankan      html  css  js  c++  java
  • 学习知识点发现的各种小tip

    FFT,NTT

    1. 多项式的点值表示法是可以直接进行+,-,*,/等运算的,考虑其定义即可。但一般加减运算都是直接系数相加减,可以少做几次NTT/FFT,降低代码时间复杂度。(甚至有可能掩饰一些代码上的错误,比如有个数组进行了一次NTT+逆NTT后%xn,将大于xn的部分系数清零了,但没有影响你所需的(即n以内的)这部分系数的大小。此时再将这个长度已缩小到n的系数序列按第一次的序列长len=n<<1来做NTT就会产生错误的点值数组,但如果直接加减则没有问题);

    2. 进行FFT/NTT时,一定记得FFT/NTT与逆FFT/NTT所用的len相同。而且在一次FFT/NTT+逆FFT/NTT的过程没完成前不能更改存储点值/系数的数组,哪怕是超过当前所求长度n的部分改变,也会影响n以内的数据的正误;

    3. 进行多项式开方,求逆,ln,exp等运算时,如有不同的函数都要用中间数组,就多开几个不同的,别图省事。这样可以防止运行过程中仍需使用的数据被其他函数覆盖,也可以少清几个零。不过在不需卡常时,还是每次使用都把数组清空一遍,该赋初值的就赋初值。因为有些看着为零的变量/没被使用过的数组,不知道什么时候就被调用过了,多项式那么多函数套在一起,检查起来也费劲,还不如多写几行代码。

    4. 像赋初值,求len,求反转数组rev[i],多项式相乘的使用频率高的都写成函数,易读又好查错。

    像上面那些显而易见的细节只有我这种蒟蒻才会需要吧……学多项式和生成函数感觉自己快退役了5555~

    莫比乌斯反演

    莫比乌斯反演中常见的做法有:

    1. ([gcd(x,y)==1])(varepsilon(gcd(x,y)))化为(Sigma_{p|gcd(x,y)}mu(p))
    2. 改变枚举顺序,将枚举因子提前,然后通常可以运用整除分块:(Sigma_{i=1}^nSigma_{j=1}^mSigma_{p|gcd(x,y)}mu(p)Rightarrow Sigma_{p=1}^{min(n,m)}mu(p)Sigma_{i=1}^{n/p}Sigma_{j=1}^{m/p}1Rightarrow Sigma_{p=1}^{min(n,m)}mu(p)lfloor frac np floor lfloor frac mp floor)
    3. 如果有类似(Sigma_{i=1}^nf(i)Sigma_{j=1}^{n/i}g(j)h(ij))的表达,可以尝试转化为(Sigma_{t=1}^nh(t)Sigma_{p|t}f(p)g(frac tp)),然后用数据结构维护(Sigma_{p|t}f(p)g(frac tp))

    扩展中国剩余定理

    1. 中国剩余定理似乎可以用扩展中国剩余定理完全代替哦 废话,本来就是扩展嘛
    2. 扩展中国剩余定理有两种实现方法:联立和代入。现有两个方程:(x equiv a pmod {p_1},x equiv b pmod {p_2})

    联立:(x=a+t_1*p_1=b+t_2*p_2),故 (t_1*p_1-t_2*p_2=b-a)。扩展欧拉定理得解。

    代入:(x equiv a pmod {p_1}) 得出 (x+t_1*p_1=a)。求出特解(x=ans),可得通解(x=ans+t_1*p_1)。又有(x equiv b pmod {p_2}),即(ans+t_1*p_1+t_2*p_2=b) 移项得(t_1*p_1+t_2*p_2=b-ans),扩展欧拉定理得解。

    当公式有变形时,似乎代入法能更简洁地得出解法:有 (n)个形如 (w_ixequiv a_i pmod {p_i})的同余方程,已得出前 (n-1)个的解 (ans)和模数 (P),第 (n)个方程为 (wx equiv a pmod p),代入可得 (w(ans+tP)+t_1p=a),移项得 (wPt+t_1p=a-w*ans)。求出特解 (t=T),则通解 (t=T+frac{p}{gcd(p,wP)}),则前 (n)个方程的解为 (ans_n=ans_{n-1}+TP),通解为 (ans_{n-1}+(T+frac{p}{gcd(p,wP)})*P),即 (ans_n+frac{pP}{gcd(p,wP)}),前 (n)个方程的模数为 (frac{pP}{gcd(p,wP)})。例题详见[NOI2018] 屠龙勇士做法。

    路径计数问题

    翻折法:求点A(0,0)到B(n,m),不经过某一条直线的不降路径条数(即只能向上或向右的路径),可作A关于直线的对称点A',答案即为A到B的不降路径条数-A'到B的不降路径条数。
    证明:对于一条从A出发经过直线的路径,将其与直线最后的交点前的部分沿直线翻折,即可转化为一条从A'到B的路径。详见OI-wiki卡特兰数部分。

    树形背包

    有一类树形背包f[i][j],第一维表示点的编号,第二维表示子树内选的点数且限制不超过m。有如下转移:

    void dfs(int u,int last) {
    	sz[u]=1;
    	for(int k=head[u];k;k=e[k].next)
    	{
    		int v=e[k].to; if(v==last) continue;
    		dfs(v,u);
    		for(int j=0;j<=min(m,sz[u]);++j)
    			for(int k=0;k<=min(m-j,sz[v]);++k)
    				dp[u][j+k]=dp[u][j] * dp[v][k];
    	}
    } 
    

    其总复杂度可证为(O(nm))。具体见这篇博客(我没看懂,但我大受震撼)。

    取模情况下大数组合数的计算

    ({n choose m}\%p)问题中若(n)(m)均较大,当然是使用卢卡斯定理;若只是(m)较大,答案为0;若只是(n)较大呢?
    在一类特殊情况下可以直接对(n)取模:({nchoose m}*(m!))
    难道不存在一种可能:(n)取模后变得小于(m),导致答案变成0,不同于原来了?实际上这是没关系的:

    如果 (n \%mod) 后变得小于(m),那么证明 (n-val<m) ( (val) 为小于 (n) 的最大的(mod) 的倍数)。那么原式即 (n(n-1)(n-2)……(n-m+1))。这个算式中一定有一个 (mod) 的倍数,所以答案就是0。

    如果 (n \%mod) 后仍大于(m),那么将 (n(n-1)……(n-m+1))的每一项 (\% mod) ,结果肯定仍相同。

  • 相关阅读:
    16. 3Sum Closest
    17. Letter Combinations of a Phone Number
    20. Valid Parentheses
    77. Combinations
    80. Remove Duplicates from Sorted Array II
    82. Remove Duplicates from Sorted List II
    88. Merge Sorted Array
    257. Binary Tree Paths
    225. Implement Stack using Queues
    113. Path Sum II
  • 原文地址:https://www.cnblogs.com/jstcao/p/14363148.html
Copyright © 2011-2022 走看看