C. Magic Grid
题意
给一个 $n(n\%4=0)$ ,将 $0\sim n^2-1$ 填入 $n\times n$ 的矩阵里,使得每行每列的异或和相同。
int $ -2.14\times10^9 \sim 2.14\times10^9$
unsigned int $0\sim4.29 \times10^ 9$
long long $-9.22\times10^{18}\sim9.22 \times10^ {18}$
unsigned long long $0\sim1.84 \times10^ {19}$
float $-3.40\times10^{38}\sim3.40 \times10^ {38}$ 6~7
double $-1.79\times10^{308}\sim1.79 \times10^ {308}$ 15~16
long double $-1.2\times10^{4932}\sim1.2\times10^{4932}$ 18-19
$memset$ 只管后面的两个字符,然后前面的直接就复制过去, 所以 $memset( a,0x3f,sizeof(a) )$ 效果等同于 $memset( a,0x3f3f3f3f,sizeof(a) )$
$strlen()$ 的时间复杂度为 $\mathcal{O}(n)$
$s.size()$ 的返回值为 $unsigned long$
1 | int *a = new int[50]; |
1 | %f float |
1 | - 左对齐 |
1 | //scanf()读入char[] |
1 | freopen("/Users/perpeternal/Downloads/test.in", "r", stdin); |
1 | void out(int count,...){ |
1 | #pragma comment(linker, “/STACK:1024000000,1024000000”) |
-O0 表示无优化状态
-O1 表示对代码进行了优化
-O2 表示减小目标文件大小
-O3 表示减小代码段及栈空间的大小
全局:
1 | #pragma GCC optimize (2) |
部分:
1 | #pragma GCC push_options |
1 | //这是两个预定义类(类型),定义的变量可以用重载好的 () 运算符获取随机数 |
1 | assert(0); //终止程序,报re |
1 | int isfinite(x); 判断x是否有限,是返回1,其它返回0; |
1 | bitset<4> bitset1; //无参构造,长度为4,默认每一位为0 |
1 | //在结构体外重载结构体小于运算符 |
1 | vector<int>v1; |
1 | struct node{ |
1 | typedef struct UrlKey |
1 | struct node{ |
1 | #include <iostream> |
1 | string s(str) //拷贝构造函数 生成str的复制品 |
test.cpp - 预处理(Pre-processing) - test.i - 编译(Compiling) - test.s - 汇编(Assembling) - test.o - 链接(Linking) - test
-E 选项使用g++/gcc将源代码预处理后不执行其他动作。
下面的命令将test.cpp预处理,并在标准输出中显示:
1 | g++ -E test.cpp |
后面加上 -o 选项表示将源代码预处理后输出在指定文件中,比如test.i:
1 | g++ -E test.cpp -o test.i |
-S 选项使用g++/gcc将预处理后的文件编译,翻译成汇编代码。只编译不汇编
下面的命令将会编译test.i文件,并自动在当前文件夹生成test.s文件
1 | g++ -S test.i |
若要指定其他输出名,则需 -o 指定,比如生成名为xxx.s的汇编代码文件
1 | g++ -S test.i -o xxx.s |
-c 选项将编译生成的test.s文件生成二进制目标代码
下面的命令将在当前文件夹自动生成test.o的二进制目标代码文件
1 | g++ -c test.s |
如果要指定输出文件名,则需 -o 指定,比如生成xxx.o的二进制目标代码文件
1 | g++ -c test.s -o xxx.o |
链接阶段是将相关的目标文件链接起来,形成一个整体,生成可执行文件
无选项链接
下面的命令会把二进制目标文件test.o所需的相关文件链接成一个整体,并在当前文件夹自动生成一个名为a.out的可执行文件
1 | g++ test.o |
如果要执行这个可执行文件,需要输入命令
1 | ./a.out |
当然也可以指定生成的可执行文件的文件名
1 | g++ test.o -o test.exe |
当然g++/gcc也可以直接把源代码直接生成可执行文件
下面的命令将test.cpp直接在当前文件夹生成a.out可执行文件,若要指定文件名,可使用 -o 选项
1 | g++ test.cpp |
也可以将多个源代码编译链接成一个可执行文件
下面的命令将test.cpp直接在当前文件夹生成a.out可执行文件,若要指定文件名,可使用 -o 选项
1 | g++ test1.cpp test2.cpp |
如果要使用C++11版本特性,则需要使用 -std=c++11 选项
1 | g++ -std=c++11 test.cpp -o test.exe |
先在每个箱子里面放 $1$ 个球, 然后还剩下 $n-m$ 个球了, 就转化成了上一种情况, $dp_1[n-m][m]$
一共有 $n-1$ 个空隙, 要插 $m-1$ 个板, $C_{n-1}^{m-1}$
先给每个盒子一个球, 把问题转化为不能空的情况, 相当于 $n+m$ 个小球放入 $m$ 个盒子且不能空, $C_{n+m-1}^{m-1}$
从 $n$ 个不同的物品中选取 $m$ 个,每种物品可以取多次,问方案数。
设从每种物品中取 $a_i$ 个,显然 $\sum a_i=m$ ,所以就相当于将 $m$ 个相同的球放入 $n$ 个不同的箱子里。
第二类斯特林数
$dp_2[n][m]$ 代表 $n$ 个小球放入 $m$ 个不同的盒子且不能空的方法
对于一个置换 $f$, 若一个染色方案 $s$ 经过置换后不变,称 $s$ 为 $f$ 的不动点。将 $f$ 的不动点数目记为 $c(f)$,则可以证明等价类数目为所有的 $c(f)$ 平均值。
例子: 一正方形分成 $4$ 格,$2$ 着色,有多少种方案?
对于这 $16$ 种方案可以归一下类:
不动:
转 $90$ 度 :$a2=(1)(2)(6 ,5, 4, 3)(10, 9 ,8 ,7)(11, 12)(16 ,15 ,14 ,13) $
转 $180$ 度:$a3=(1)(2)(3 ,5)(4, 6)(7, 9)(8, 10)(11)(12) (13, 15)(14, 16) $
$(a,b,c)$ 表示可以通过 $a,b,c$ 旋转得到
所以共有 $\frac {16+2+4+2}4=6$ 种方案.
假设一个置换有 $k$ 个循环,易知每个循环对应的所有位置颜色需一致,而任意两个循环之间选什么颜色互不影响。因此,如果有 $m$ 种可选颜色,则该置换对应的不动点个数为 $m^k$。用其替换 $burnside$ 引理中的 $c(f)$,即 $c(f)=m^k$ 得到等价类数目为:
不动:$a1=(1)(2)(3)(4) $
旋转 $90$ 度:$a2=(1, 2, 3, 4)$
旋转 $180$ 度 :$a3=(1 ,3)(2 ,4)$
旋转 $270$ 度:$a4=(1, 4, 3, 2)$
由$Polya$ 定理得,共有 $\large\frac {2^4+2^1+2^2+2^1}4=6$ 种方案。
如果要把 $n$ 个物品放入 $m$ 个容器中,至少有一个容器中的物品的数量 $\large\ge\lceil\frac n m\rceil$
给 $n$ 个数,找出一些数,其和为 $n$ 的倍数
有 $n$ 个前缀和,如果没有等于 $0$ 的,那么剩余的数的取值为 $1\sim {n-1}$ ,必定有一个数使用了两次
通俗解释
在 $6$ 个或更多人中,或者有 $3$ 个人,他们中的每两个人都互相认识;或者有 $3$ 个人,他们中的每两个人都彼此不认识。记为 $K_6\to K_3,K_3$
一般解释
对于一个给定的两个整数 $n,m\ge2$,则一定存在一个最小整数 $r$,使得用两种颜色(红色或蓝色)无论给 $K_r$ 的每条边如何染色,总能找到一个红色的 $K_m$ 或者蓝色的 $K_n$ 。显然,当 $p\ge r$ 的时候,$K_p$ 亦满足这个性质。
$f(i)=f(i-1)+f(i-2),f(1)=f(2)=1$
与集合子集
斐波那契数列的第 $n+2$ 项同时也代表了集合 {1,2,…,n} 中所有不包含相邻正整数的子集个数。
如果 $f(k)$ 能被 $x$ 整除,则 $f(k*i)$ 都可以被 $x$ 整除。
求递推公式 $a(1)=1,a(n+1)=1+\frac 1 {a(n)}$ 的通项公式 $a(n)= \frac {fib(n+1)}{fib(n)}$
矩阵快速幂
1 | struct matrix { |
$F_0=2,F_1=1,F_n=F_{n-1}+F_{n-2}$
通项为
$n$ 阶的法里数列是 $0$ 和 $1$ 之间最简分数(分母不大于 n )的数列,由小至大排列,每个分数的分母不大于 $n$。
已知两个法里数 $\frac ab$和 $\frac c d$,那么两者之间的法里数就是$\frac {a+c} {b+d}$
$F_n$ 包含了 $F_{n-1}$ 的全部项
$|F_n|=|F_{n-1}+\phi(n)|$
$|F_n|\sim \frac {3n^2} {\pi^2}$
若 $\frac a b,\frac c d(\frac a b<\frac c d)$ 是法里数列的邻项,则它们之差为 $\frac 1 {bd}$
F1 = {0⁄1, 1⁄1}
F2 = {0⁄1, 1⁄2, 1⁄1}
F3 = {0⁄1, 1⁄3, 1⁄2, 2⁄3, 1⁄1}
F4 = {0⁄1, 1⁄4, 1⁄3, 1⁄2, 2⁄3, 3⁄4, 1⁄1}
F5 = {0⁄1, 1⁄5, 1⁄4, 1⁄3, 2⁄5, 1⁄2, 3⁄5, 2⁄3, 3⁄4, 4⁄5, 1⁄1}
F6 = {0⁄1, 1⁄6, 1⁄5, 1⁄4, 1⁄3, 2⁄5, 1⁄2, 3⁄5, 2⁄3, 3⁄4, 4⁄5, 5⁄6, 1⁄1}
F7 = {0⁄1, 1⁄7, 1⁄6, 1⁄5, 1⁄4, 2⁄7, 1⁄3, 2⁄5, 3⁄7, 1⁄2, 4⁄7, 3⁄5, 2⁄3, 5⁄7, 3⁄4, 4⁄5, 5⁄6, 6⁄7, 1⁄1}
F8 = {0⁄1, 1⁄8, 1⁄7, 1⁄6, 1⁄5, 1⁄4, 2⁄7, 1⁄3, 3⁄8, 2⁄5, 3⁄7, 1⁄2, 4⁄7, 3⁄5, 5⁄8, 2⁄3, 5⁄7, 3⁄4, 4⁄5, 5⁄6, 6⁄7, 7⁄8, 1⁄1}
进出栈问题
一个足够大的栈的进栈序列为 $1,2,3,⋯,n$ 时有多少个不同的出栈序列?
我们可以这样想,假设 $k$ 是最后一个出栈的数。比 $k$ 早进栈且早出栈的有 $k-1$ 个数,一共有 $h(k-1)$ 种方案。比$k$ 晚进栈且早出栈的有 $n-k$ 个数,一共有 $h(n-k)$ 种方案。所以一共有 $h(k-1)\times h(n-k)$ 种方案。显而易见,$k$ 取不同值时,产生的出栈序列是相互独立的,所以结果可以累加。$k$ 的取值范围为 $1$ 至 $n$,所以结果就为$h(n)= h(0)h(n-1)+h(1)h(n-2) + … + h(n-1)h(0)$
有n个结点,问总共能构成几种不同的二叉树。
我们可以假设,如果采用中序遍历的话,根结点第k个被访问到,则根结点的左子树有k-1个点、根结点的右指数有n-k个点。k的取值范围为1到n。讲到这里就很明显看得出是卡特兰数了。
凸多边形的三角形划分
一个凸的n边形,用直线连接他的两个顶点使之分成多个三角形,每条直线不能相交,问一共有多少种划分方案。
选择一个基边,显然这是多边形划分完之后某个三角形的一条边。图中我们假设基边是p1pn,我们就可以用p1、pn和另外一个点假设为pi做一个三角形,并将多边形分成三部分,除了中间的三角形之外,一边是i边形,另一边是n-i+1边形。i的取值范围是2到n-1。所以本题的解$c(n)=c(2)c(n-1)+c(3)c(n-2)+…c(n-1)c(2)$。令t(i)=c(i+2)。则$t(i)=t(0)t(i-1)+t(1)t(i-2)…+t(i-1)t(0)$。很明显,这就是一个卡特兰数了。
$n$ 个 $1$ , $n$ 个 $-1$ ,构成的排列中,满足任意一段前缀和都 $\ge0$ 或 $\le0$ 的数量为 $h(n)$,可以将 $1$ 看作入栈,将 $-1$ 看作出栈
$x$ 个 $1$ , $y(x\ge y)$ 个 $-1$ ,构成的排列中,满足任意一段前缀和都 $\ge0$ 的数量为 $C(x+y,x)-C(x+y,x+1)$,可以将 $1$ 看作入栈,将 $-1$ 看作出栈
n个元素的集合的划分方案数
贝尔三角形
第一行第一项是1, $a(1,1)= 1$
对于$n>1$,第 $n$ 行第一项等同第 $n-1$ 行最后一项, $ a(n,1)=a(n-1,n-1)$
对于$m,n>1$,第 $n$ 行第 $m$ 项等于它左边和左上方的两个数之和, $a(n,m)=a(n,m-1)+a(n-1,m-1)$
同余性质 (p是不大于100的素数)
其绝对值是包含 $n$ 个元素的集合分作 $k$ 个环排列的方案数
将 $n$ 个不同的元素拆分成 $m$ 个集合的方案数
从 $(0,0)$ 到 $(n,n)$ 的格路中,只能使用 $(1,0),(0,1),(1,1)$ 三种移动方式,始终位于对角线下方且不越过对角线的路径数, $1, 2, 6, 22, 90, 394, 1806, 8558, 41586, 206098,… (OEIS A006318)$
五边形数
$\large p(n)=\frac {(3*n^2-n)}2$
前几个五边形数:1, 5, 12, 22, 35, 51, 70, 92, 117, 145, 176, 210, 247, 287, 330, 376, 425, 477, 532, 590, 651, 715, 782, 852, 925, 1001 ………
广义五边形数:
n的取值0,1,-1,2,-2,3,-3…….
前几个广义五边形数:0, 1, 2, 5, 7, 12, 15, 22, 26, 35, 40, 51, 57, 70, 77, 92, 100, 117, 126, 145, 155, 176, 187, 210, 222, 247, 260, 287, 301, 330…..
五边形数测试
中心五边形数
中心六边形数(相邻两个广义五边形数之和)
费马多边形数定理: 每一个正整数最多可以表示为 n 个 n-边形数 的和
$(n-1)^k=n^k+C(k,1)n^(k-1)(-1)+C(k,2)n^(k-2)(-1)^2+…+C(k,k)*(-1)^k$
$(n-2)^k=[(n-1)-1]^k=(n-1)^k+C(k,1)(n-1)^(k-1)(-1)+C(k,2)(n-1)^(k-2)(-1)^2+…+C(k,k)*(-1)^k$
$(n-3)^k=[(n-2)-1]^k=(n-2)^k+C(k,1)(n-2)^(k-1)(-1)+C(k,2)(n-2)^(k-2)(-1)^2+…+C(k,k)*(-1)^k$
…
$2^k=(3-1)^k=3^k+C(k,1)3^(k-1)(-1)+C(k,2)3^(k-2)(-1)^2+…+C(k,k)*(-1)^k$
$1^k=(2-1)^k=2^k+C(k,1)2^(k-1)(-1)+C(k,2)2^(k-2)(-1)^2+…+C(k,k)*(-1)^k$
这n-1个式子相加,得:
$1^k=n^k+C(k,1)(-1)[2^{k-1}+3^{k-1}+…+n^{k-1}]+C(k,2)(-1)^2[2^{k-2}+3^{k-2}+…+n^{k-1}]+…+(n-1)C(k,k)(-1)^k$
如果令关于k的函数$S(k)=1^k+2^k+…+n^k$
则$1=n^k+C(k,1)(-1)[S(k-1)-1]+C(k,2)(-1)^2[S(k-2)-1]+…+(n-1)*(-1)^k$
由此可以得出S(k-1)关于S(k-2)、S(k-3)、…、S(2)和S(1)的地推公式
已知
$S(1)=1+2+…+n=\frac {n(n+1)} 2 $
$S(2)=1^2+2^2+…+n^2=\frac {n(n+1)(2n+1)}2$
$S(3)=1^3+2^3+…+n^3=S(1)^2$
若递推式为 $f(n)=a\times f(n-1)+b\times f(n-2)$ ,其矩阵关系为
寻找最小的 $n$ 使得
令 $c=a^2+4b$ ,分类讨论
把n素因子分解,即 $n=p_1^{a_1} p_2^{a_2} · · · *p_k^{a_k}$
分别计算Fib数模每个$p^m$的循环节长度,假设长度分别是$x_1,x_2,x_3, · · · ,x_k$
那么Fib模n的循环节长度$L=lcm(x_1,x_2,x_3, · · · ,x_k)$
1 | //简单算法 |
对于一棵树来说,删去该树的重心后,所有的子树的大小不会超过原树大小的 $\large\frac 1 2$。树的重心还有一个性质,是相对于树上的其他点而言的,就是删去重心后形成的所有子树中最大的一棵节点数最少。换句话说,就是删去重心后生成的多棵子树是最平衡的。一棵树的重心至多有两个。
我们可以很容易的在一次DFS过程中求出所有节点的 $size$,即子树大小。我们每搜索完一个节点 u 的儿子 v,就判断 size[v] 是否大于 $\frac n 2$,然后在搜索完所有儿子后计算出本节点的 $size$,再判断 $n-size[u]$ 是否大于 n/2( n-siz[u] 是节点 u 上面的连通块大小)即可求出重心,时间复杂度 O(n)。
树上的最长路径,可以有多条。
法一:任取树中的一个节点x,找出距离它最远的点y,那么点y就是这棵树中一条直径的一个端点。我们再从y出发,找出距离y最远的点就找到了一条直径。对于树中的任一个点,距离它最远的点一定是树上一条直径的一个端点。
法二:定义F[i]表示从i出发向远离根节点的方向走的最长路径的长度,G[i]表示从i向远离根节点的方向走的次长路径的长度。注意F[i]和G[i]不能沿着i的同一个儿子走。特别地,如果i只有一个儿子,那么G[i]=0。答案为max(F[i]+G[i])。
1 | int lowbit(int x){ |
1 | ll n,sum[N]; |
离散化,排序,逆序对数就是下标的逆序对数,逐一加入,加上已加入的大于当前值的数量。
1 | int lowbit(int x){ |
差分,设数组 $d[i]=a[i]-a[i-1],(a[0]=0)$,则 $a[i]=\sum\limits_{j=1}^id[j]$。
1 | ll n,sum[N]; |
$\sum\limits_{i=1}^pa[i]=\sum\limits_{i=1}^p\sum\limits_{j=1}^id[j]=(p+1)\times\sum\limits_{i=1}^pd[i]-\sum\limits_{i=1}^pd[i]\times i$,所以我们需要维护两个数状数组$d[i],d[i]*i$
1 | ll sum1[N],sum2[N],n; |
定义$tree[x][y]$记录的是右下角为(x, y),高为lowbit(x), 宽为 lowbit(y)的区间的区间和。
1 | void add(int x, int y, int z){ //将点(x, y)加上z |
差分 $d[i][j]=a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1]$
1 | void add(int x, int y, int z){ |
1 | #include <cstdio> |
建树
1 | int A[N],Sum[N<<2],Lazy[N<<2]; |
建堆
1 | int Heap[n],n; |
删除-输出最小元素
1 | int delete_min(){ |
堆排序(从大到小)
1 | void heap_sort(){ |
n 个数中,找出最大(最小)的 m 个,建立一个小(大)顶堆维护当前最大(最小)的 m 个数再将剩余的推入。
1 | ll dp[N][70] |
可持久化权值线段树,因为其中的每一颗树都是一颗权值线段树。
1 | int L[N],R[N],dep[N],tot; |
对某个节点X权值加上一个数W, 查询某个子树X里所有点权的和.
对节点X到Y的最短路上所有点权都加一个数W, 查询某个点的权值.
这个操作等价于
a. 对X到根节点路径上所有点权加W
b. 对Y到根节点路径上所有点权加W
c. 对LCA(x, y)到根节点路径上所有点权值减W
d. 对LCA(x,y)的父节点 fa(LCA(x, y))到根节点路径上所有权值减W
于是要进行四次这样从一个点到根节点的区间修改.将问题进一步简化, 进行一个点X到根节点的区间修改, 查询其他一点Y时,只有X在Y的子树内, X对Y的值才有贡献且贡献值为W.当单点更新X时,X实现了对X到根的路径上所有点贡献了W.于是只需要更新四个点(单点更新) ,查询一个点的子树内所有点权的和(区间求和)即可.
对节点X到Y的最短路上所有点权都加一个数W, 查询某个点子树的权值之和.
同问题2中的修改方法, 转化为修改某点到根节点的权值加/减W
当修改某个节点A, 查询另一节点B时
只有A在B的子树内, Y的值会增加
W (dep[A] - dep[B] + 1) => W (dep [A] + 1) - W dep[B]
那么我们处理两个数组就可以实现:
处理出数组Sum1,每次更新W(dep[A]+1),和数组Sum2,每次更新W.
每次查询结果为Sum1(R[B]) – Sum1(L[B]-1) - (Sum2(R[B]) – Sum2(L[B]-1)) * dep [B].
对某个点X权值加上一个数W, 查询X到Y路径上所有点权之和.
求X到Y路径上所有的点权之和, 和前面X到Y路径上所有点权加一个数相似
这个问题转化为
X到根节点的和 + Y到根节点的和 - LCA(x, y)到根节点的和 - fa(LCA(x,y)) 到根节点的和
更新某个点x的权值时,只会对它的子树产生影响,对x的子树的每个点到根的距离都加了W.
那么我们用”刷漆”(差分前缀和),更新一个子树的权值.给L[x]加上W,给R[x]+1减去W,那么sum(1~L[k])就是k到根的路径点权和.
对节点X的子树所有节点加上一个值W, 查询X到Y的路径上所有点的权值和
同问题4把路径上求和转化为四个点到根节点的和
X到根节点的和 + Y到根节点的和 - LCA(x, y)到根节点的和 - parent(LCA(x,y)) 到根节点的
再用刷漆只更新子树.
修改一点A, 查询某点B到根节点时, 只有B在A的子树内, A对B才有贡献.
贡献为W (dep[B] - dep[A] + 1) => W (1 - dep[A]) + W dep[B]
和第三题一样, 用两个sum1,sum2维护 W (dep[A] + 1),和W.
最后答案就是sum2*dep[B]-sum1.
对子树X里所有节点加上一个值W, 查询某个点的值.
对DFS序来说, 子树内所有节点加W, 就是一段区间加W.
所以这个问题就是 区间修改, 单点查询.树状数组+刷漆.
对子树X里所有节点加上一个值W, 查询某个子树的权值和.
子树所有节点加W, 就是某段区间加W, 查询某个子树的权值和, 就是查询某段区间的和
区间修改区间求和,用线段树可以很好解决.
从根结点出发,按dfs的顺序在绕回原点所经过所有点的顺序
以每个点为原点,划分八个区域,将每个区域里距离 $S$ 最近的点连边,再跑最小生成树算法。
1 | struct point{ |
对区间询问按左端点排序,将序列分成 $sqrt(n)$ 个长度为 $sqrt(n)$ 的块,若左端点在同一个块内,则按右端点排序。
奇偶排序
在块的序号为奇时,对 r 按从小到大排序,反之按从大到小排序
1 | struct node { |
加上一个时间维,表示操作的时间。
即把询问 $[l,r]$ 变为 $[l,r,time]$
这一次我们排序的方式是以 $n^{\frac 2 3}$ 为一块,分成了 $n^{\frac 1 3}$ 块,第一关键字是左端点所在块,第二关键字是右端点所在块,第三关键字是时间。
1 | int uni[N]; |
找出数组中数量超过一半的数
1 | int findMainElement(const int* array, size_t size) { |
1 | int b=0,sum=-100000000,l,r; |
思路一:
把环形最大子段和可以看做两部分。第一部分——正常最大子段和,第二部分——跨越a[0] 和 a[n-1]的最大子段和。 第一部分可以用O(n) 求出,第二部分我们从a[0] 开始计算 0~n-2 的最大和,记录结束位置position1。 再从a[n-1] 开始计算 n-1~1的最大和,记录结束位置 position2。
position2 > position1 则第二部分最大和 a[0] + … a[position1] + a[position2] + …a[n-1]
position2 <= position1 则第二部分最大和 a[0] + ……. a[n-1]
思路二: 数组总和 - 最小子段和
设F(i, j) 为 在前i个元素中选j个子段的最大和,且包含元素a[j]. 那么对于a[j] , 1) a[j] 自己组成第 j 子段 ; 2) a[j] 包含于第 j 子段中;
dp[i] = sum[i] - min(sum[j] | i- m <= j <= i)
利用单调队列优化.如果来了一个前缀,肯定下标是比在队列里的是靠后的,如果它的值还比队列里的小,那么队列里的元素就没有必要存在了,就把它们踢出去。
这样的话最小值就是队首的元素,当然在用队首元素的时候还要在看一下当前的队首元素还符不符合限制条件,如果不符合就弹出。
1 | ll fun(ll m, ll a[], int len) { // a的下标从1开始 |
要么正的最大,要么负的最小。 所以问题解等于max{abs(最大子段和), abs(最小子段和)}
对b排序(保留index 信息)
求排序后数组相邻位置差最小
1 | int l=1,r=0,q[N];//q[i]表示从 i 开始长度为 len 的序列中的最小值的下标 |
$1-n$ 所有数中,数位 $0-9$ 的数量
$f[i]$ 表示前 $i$ 位出现的数码次数
1 | ll f[20],cnt[10]; |
只要找到一个子局面是P-position(先手必败)就能说明是N-position(后手必败),反之为P-position。
mex(minimal excludant)是定义在整数集合上的操作。它的自变量是任意整数集合,函数值是不属于该集合的最小自然数。
终止状态的SG值显然为0,并且SG值为0的状态就是P状态,SG值不为0的状态就是N状态.
有n堆石子,石子数目=分别为$a_1,a_2,a_3 · · · a_n$,A,B两人每次可以选一堆石子取走任意多个
P-position: $a_1\wedge a_2\wedge · · · \wedge a_n=0$
两堆石子,个数为$x_1,x_2$; A,B轮流取石子,规定要么只取一堆的任意多个,要么在两堆里取同样任意多个
P-position: (0,0)(1,2)(3,5)(4,7)
取正无理数α,β,使得$\frac 1\alpha+\frac 1 \beta=1$
构造两个数列a,b,它们的通项为$a_n=⌊αn⌋,b_n=⌊βn⌋$
那么这个数列显然是正整数序列,Beatty定理指出,两个数列都是严格递增的,并且每个正整数在两个数列中只出现一次
有一堆个数为n的石子,A,B轮流取石子,满足:
P-position: 1,2,3,5,8,13,21,34,55,89,…(Fibonacci)
任何正整数可以表示为若干个不连续的Fibonacci数之和。
n堆石子,每堆石子的数量为$x_1,x_2,….x_n$,A,B轮流操作,每次可以选第k堆中的任意多个石子放到第k-1堆中,第1堆中的石子可以放到第0堆中.
P-position: $x_1 \wedge x_3\wedge x_5…\wedge x_{2*n+1}=0$
有n堆石子,A,B两人每次可以选一堆石子取走任意多个,取到最后一个石子的人为输.
N-position: 所有堆石子数都为1且SG值为0 ; 至少有一堆石子数大于1且SG值不为0
两个人在一个1*N的格子内挪动棋子,刚开始在若干个位置上有若干个棋子,每一个选手可以进行的操作时选择一个棋子并把它向左方移动,当然不能越过其它的棋子,也不能超出边界。
按位置升序排列后,从后往前把他们两两绑定成一对。如果总个数是奇数,就把最前面一个和边界(位置为0)绑定。对手移动左,你移动相同步数;对手移动右,表示取相应的石子.
K=1 P-position: 2^k 先手的策略是取lowbit(n)
K=2 P-position: Fibonacci Nim
K>2 (K=1或K=2也可以用次方法构造)仿照斐波那契博弈的构造方法构造一个数列an b[]作为辅助数组表示前i个的a能够按规则构造出的最大的数
1 | a[i+1]=b[i]+1; |
1 | typedef double db; |
1 | struct Point{ |
1 | struct PolarPoint { |
1 | struct Line { |
1 | struct Circle { |
用二次曲线逼近原函数,在平面直角坐标系中,由三点 $(x_1,y_1),(x_2,y_2),(x_3,y_3) (x_1<x_2<x_3,x_2=\frac{x_1+x_3} 2)$ 确定的抛物线 $y=f(x)$ 的定积分为
将要积分的区域 $[L, R]$ 划分成 $n$ 份,横坐标为 $x_0\sim x_n$,对应的函数值分别为 $y_0\sim y_n$ 其结果为
对要积分的区域 $[L, R]$ 分成两半 $[L, mid]$ 和 $[mid, R]$,如果用二次曲线对 $(L, mid, R)$ 求出的积分值,和对 $(L, \frac {L+mid} 2, mid)$ 和 $(mid,\frac {L+mid} 2, R)$ 分别积分再加起来的值,相差不超过某个精确度,那么就可以停止划分。
1 | // 1 |
1 | // 2 |
1 | struct Edge{ |
1 | //Floyd-Warshall算法核心语句 |
1 | bool bellman_ford(int start, int n){ |
1 | const int inf=0x3f3f3f3f; |
1 | struct Edge{ |
1 | for(int i=1; i<=n; i++) |
求解差分约束系统,都可以转化成图论的单源最短路径(或最长路径)问题。
我们观察上面例子中的不等式,都是x[i] - x[j] <= a[k],可以进行移项,成为x[i] <= x[j] + a[k],我们令a[k] = w(j, i),dis[i]=x[i],并使i=v,j=u,那么原始就变为:dis[u]+w(u,v)>=dis[v],于是可以联想到最短路模型中的一部分代码
但是好像不等号方向刚好相反,但其实这并不矛盾,上面的代码要实现的是使dis[u]+w(u,v)>dis[v],而对于不等式,我们进行建边的操作:对于每个不等式 x[i] - x[j] <= a[k],对结点 j 和 i 建立一条 j -> i的有向边,边权为a[k],求x[n-1] - x[0] 的最大值就是求 0 到n-1的最短路,两者刚好吻合。所以求解差分约束问题就转化为了最短路问题。差分约束
求解不等式组,当把不等式整理成 $d[a]+w<=d[b]$ 时,我们求最长路。整理成 $d[a]+w>=d[b]$ 时,我们求最短路。在一个未知数定死的情况下,最短路求得是最大值,最长路求得是最小值。
1 | #include<cstdio> |
1 | int n,m,ans; |
补图的最大团
1 | import java.io.*; |
1 | //System.in,只能读取单个字符 |
1 | String temp1 = "-1000000000000000000000000000000000000"; |
1 | String temp1 = "1.2222222222222222222222222"; |
1 | Vector<E> v = new Vector<E>(); |