求逆元和组合数模板
求逆元
$O(n)$求逆元
1 | ll inv[maxn]; |
$O(n)$求阶乘
1 | ll f[maxn]; |
求$n\choose k$
1 | ll cur,p[maxn],q[maxn],inv[maxn]; |
求$A^k_n$
1 | int A(int n,int k){ |
1 | ll inv[maxn]; |
1 | ll f[maxn]; |
1 | ll cur,p[maxn],q[maxn],inv[maxn]; |
1 | int A(int n,int k){ |
给一个数列,求数列中$l,r$范围内最大值和最小值的差。
st表模板题。求两次rmq即可。
1 |
|
一个由左括号和右括号组成的矩阵,定义矩阵的权值是矩阵中匹配的行数和列数的和。
一道比较典型的构造题。
如果行数或者列数是奇数那么矩阵显然是奇数的行或列匹配不了。
(())
(())
(())
当情况很多有两个变量的时候我们可以假设一个变量小于另一个变量,假设$h\leq m$。
构造过程还是题解比较清晰。
首先,第一行、最后一列中最多只有一个能够匹配,第一列、最后一行也只有一个能够匹配(考 虑右上角和左下角的括号选取方法),故答案不会超过 w+h−2。 当 h = 2 时,每一列可以构造一对匹配,这样答案已经到达上界。 当 h = 4 时,可以如下构造:
( ( ( ( ( (
) ) ) ) ) )
( ( ( ( ( (
) ) ) ) ) )
这样答案是 w+h−3。
若存在更优的答案,则必有一个边界能够匹配,不妨设是第一列。这样,就已 经有除第一行以外的两行(右括号开头的行)不匹配了,而第一行和最后一列中至少有一个不匹配, 因此最优解不会超过 w+h−3。
当 h≥6 时,可以如下构造:
( ( ( ( ( ( ( (
( ) ( ) ( ) ( )
( ( ) ( ) ( ) )
( ( ( ( ) ) ) )
( ( ) ( ) ( ) )
) ) ) ) ) ) ) )
答案是 w+h−4。同理可证明不存在更优的方法。
在实际操作的时候如果$h>m$可以将矩阵反转一下。就ok了。
1 |
|
神仙dp题
将数字从大到小一次排列,从大往小取.
构造一个三维$dp[now][j][k]$,表示放入$now$数字的时候有$i$行和$j$列有数字下的情况。为了防止数字成为平衡位置,每次放置的位置都要放置在之前放置元素所在的列或者行上,如果不这么放置的话,他就会成为剩下当前行和当前列最大的(就没能有比他大的数字了)。
初始化,因为第一个数字可以任意存放所以$dp[0][1][1]=m*n$。
转移方程:
该点放置位置上行和列都有元素,那就是有$i$列和$j$行可以存放。剩下的位置是$j*k-i+1$
,$dp[next][j][k]+=dp[now][j][k]*(jk-i+1)$
该点放置位置上列已经有元素了,但是行上没有元素,从位置的行数减一转移加了一行$dp[next][j][k]+=dp[now][j-1][k]*j(n-i+1)$
同理如果行有元素的话。$dp[next][j][k]+=dp[now][j][k-1]*i(m-j+1)$
1 |
|
ST表示用来求解给定区间RMQ的最值问题。
预处理复杂度:$O(nlongn)$,查询复杂度$O(1)$。
将原数组分成以2幂次的区间块,用$mn[i][j]$表示从$j$到$j-2^i-1$的最小值,最小值显然等于$$min(前半段最小值,后半段中最小值)$$从而得到递推式子
$$min[i][j]=min(mn[i-1][j],mn[i-1][j+2^{i-1}])$$
1 | p[0] = 1; |
定理1:$$2^{log(a)}>a/2$$
查询$x$到$y$的最小值可以假设$len=y-x+1,t=log(len)$,根据定理1,$2^t>len/2$,那么位置过了一半之后最小值的可能就落在了$x$后面的$2^t$和$y$前面的$2^t$。式子为$$mmin = min(mn[t][x],mn[t][y-2^t+1])$$
1 | int t = Log[y-x+1]; |
Reference:https://blog.csdn.net/hanks_o/article/details/77547380
标程的set+bfs貌似有漏洞。
1 | 5 6 |
这个数据就可以hack掉了。
所以我果断copy了dls队伍的代码。(用边做)
1 |
|
时间卡的非常紧。优化了很多终于2.4s过了。
$$O(n^2)$$
1 |
|
如果觉得我的题解看不懂可以去看 大佬的题解
将一颗树节点染成白色或者黑色,减去几条变使得每个联通分支都有一个黑色节点,问有多少种减边方案。
树状dp+dfs
下次看到两种状态加点的。dp应该想到用2维。
1 |
|
1 | int inv[maxn]; |
1 | ll extend_gcd(ll a,ll b,ll x,ll y){ |
给出几个点,让你求出在某个点的右边和上面最接近他的点是哪一个点。
线段树+set应用
对$x$进行离散化处理,对于每一个$x$进行建一个set,用线段树维护$x$之间的$y$的最大值。对于给出点的右上点,我们可以用二分来set搜索,还有在线段树中优先搜索左边靠近给出点的点。
这是我第一次看到离散化的线段树应用。哭泣
1 |
|