笔记1

sort函数:把数组从小到大排序

max函数:求出两个数的最大值

min函数:求出两个数的最小值

unique函数:使用前提是先排好序,再使用,效果是去重

merge_sort归并排序

reverse函数:翻转数组

random_shuffle函数:把a[1]到a[n]随机打乱

swap函数:交换两个数

没有单调性不能二分

位运算运行速度比加减乘除取模运算速度快

位运算符号有:& ^ |

只有两个矩阵的行和列一样时,才能进行矩阵的加减法。只有一个矩阵的行等于另一个矩阵的列时,才能进行乘法

矩阵乘法有结合律,但是没有交换律

搜索问题分为:

  • 最优解问题

  • 可行解问题

  • 解数量问题

必须是最优解问题,每一步的代价都是最小步数,才能用bfs,其余问题都用dfs

优化技巧:

  • 剪枝:少搜一些无用状态,分为可行性剪枝和最优性剪枝

  • 卡时

  • 随机顺序搜索

全局变量在堆空间,局部变量在栈空间

使用long long类型的变量,可以把浮点数强制转化成整数

堆空间为256M,可以存6.4×10的7次方个int,栈空间为64KB,只能存16384个int

堆默认定义为大根堆,栈是先进后出(一个桶),队列是先进先出:FIFO(first in first out)

单调队列要用手写队列,用单调递增队列来求最小值,用单调递减队列来求最大值。

归并排序核心思想就是分治,分完再治。

顺序赋值比随机顺序赋值更快。

从起点和重点同时开始bfs直到在中间某个位置相遇叫双向bfs

由点与边构成的元素分类:有向图,无向图

度:度分为入度,出度,只会出现在有向图,无向图只有度这个概念。

入度:指向这个点的边的总数,顶点v的度是指与顶点v相连的边的数目

出度:从这个点出去的点的总数,顶点v的度数为以顶点v为起点的边的数目和

度(无向图):链接这个点的总数,在无向图中,顶点v的度是指与顶点v相连的边的数目。

自环:自己连接自己,也就是一条边的起点和终点为同一个点

路径:从一个点到另一个点的过程所经过的边

简单路径:不能走重复点和边的路径

环:终点 = 起点的路径

简单环:简单路径和环的集合体,保证起点 =终点且除起点(终点)外不能经过重复的点和边的路径。

连通:两个点能够通过路径到达

连通图:一个图所有的边都能互相到达

特殊类型的图:树(无向 无环 联通)

森林(无向 无环)

有向树 (有向 无环)

外向树(所有边都朝外)

内向树 (所有边都指向一个点)

章鱼图/基环树(有环且只有一个环, 中间的点可以延伸出一棵树)

仙人掌(有多个环)

(边)仙人掌:无向联通且有多个环的图(但要满足任何一条边都只在一个环中)

仙人掌图:

  • 边仙人掌

  • 点仙人掌

DAG(有向无环图)

注:链式结构既是外向,又是内向

图的基本要素

  • 点和边(树是有点和有边的一种结构)。

二分图匹配问题:

  • 在二分图中找到尽量多的点,使得能够互相匹配,但是每个点只能用一次。

二分图一定是无向图。

如果把章鱼的环删掉一条边,就可以变成一个树

树任意加上一条边就是章鱼

染色法:把一个点染色为 1,然后一层一层向外染色。如果一条边连接的两个点的颜色一样,就说明不是二分图,否则就是。

拓扑排序:针对 DAG。

对有向图中的每一个点进行排序,使得最后的排序结果都是从左向右指的。

不断删除入度为0的点,然后不断把入度为0的点加入答案。

那如何删除一个点呢?其实不需要删除,只需要将入度减掉即可。

最短路问题可以分为两类:

  • 单源最短路问题

  • 多源最短路问题

单源最短路问题:一个起点到其他点最短路

多源最短路问题:多个起点到其他点最短路

最短路的三角不等式:dist[i][j]<=dist[i][k]+dist[k][j]

解决多源最短路的算法:flogd:dist[i][j][k],意思是从j走到k,中间经过很多点,中间节点的编号必须都<=i

所有的动态规划(DP)题中,都包含状态,转移方程,初始化条件

从一张 m 条边的图中找 n−1 条边,使得找出来的边和已有的点构成一棵树,组成的图就叫做原图的生成树。一个生成树的大小是选出来的所有边的边权之和。大小最小的生成树被称为 最小生成树。

单源最短路:求一个起点到其他点的最短路,起点是固定的。

多源最短路:求多个起点到其他点的最短路,起点不固定。

强连通分量定义在有向图,找到点边使互相能走到就构成了一个强连通分量,独立的点也可以构成一个强连通分量,找强连通分量要找环

连到自己祖先的边叫回边,反之叫做横叉边,横叉边虽然不能组成环,但能扩大一个环

DP有:树形DP,背包DP,区间DP,排列DP,数位DP,状压DP,插头DP,博弈DP,不能归类到其他DP的DP叫一般DP

分治算法的核心思想就是“分而治之”。

大概的流程可以分为三步:分解 -> 解决 -> 合并。

  • 分解原问题为结构相同的子问题。

  • 分解到某个容易求解的边界之后,进行递归求解。

  • 将子问题的解合并成原问题的解。

分治法能解决的问题一般有如下特征:

  • 该问题的规模缩小到一定的程度就可以容易地解决。

  • 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质,利用该问题分解出的子问题的解可以合并为该问题的解。

  • 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。

二叉搜索树具有以下性质:

  • 这是一颗二叉树

  • 每个节点的左儿子比自己小

  • 每个节点的右儿子比自己大

二叉搜索树又该如何建立呢?

  • 将节点从根节点开始插入

  • 与当前节点比较大小

  • 如果比当前节点储存的值大,向右递归

  • 如果比当前节点储存的值小,向左递归

注意:

如果我们从小到大插入二叉搜索树,就会出现一条链的情况。

那么如何避免?

  • 尽可能随机地将元素插入二叉搜索树中;

  • 当我们发现一个二叉搜索树的高度很接近于元素的数量时,我们就将其进行局部推倒重建;

  • 选取值为中间的一个元素为根,再次进行插入操作;

  • 平衡树的做法(不属于 NOIP 的考纲)。

二叉堆是一种特殊的二叉树,满足任意上面节点的值都比下面节点大的叫做大根堆,满足任意上面节点的值都比下面节点小的叫做小根堆。

一般二叉堆能解决什么问题呢?

  • 在O(log n)的时间内插入一个元素

  • 在O(log n)的时间内删除一个元素

  • 在O(1)的时间内查询最大值

二叉堆插入操作如何实现呢?(以大根堆为例)

从根节点开始,插入一个值,如果当前值比根节点大,与根节点交换存储的值,然后往子树大小更小的儿子递归,直到某个儿子大小为0(即没有某一边儿子),新建一个节点来储存这个值,这样我们可以保证插入操作一定不超过log n次递归。

二叉堆删除操作如何实现呢?(以大根堆为例)

将当前节点权值视为0,与最大的儿子交换权值并递归,直到节点是一个叶子(无左右儿子),然后删除该叶子。,这样我们可以保证删除操作一定不超过log n次递归。删除根节点即可弹出最大值。

二叉堆查询最大值操作如何实现呢?(以大根堆为例)

取根节点的权值即可。

一般实战中二叉堆怎么写呢?

使用STL中的priority_queue,对于删除操作,记录哪些元素被删除了,如果堆顶是这个元素那就再多弹出一次即可。

线段树解决什么问题呢?

各种各样的序列操作问题,例如最常见的问题:

有一个长度为N的序列(可能有初始值),然后有Q次操作,每次操作可能是以下两种之一:(1)修改一个位置的值 (2)查询一个区间的权值和 1≤N,Q≤10^5

如何构建线段树?首先令根节点的范围为[1,N],然后递归建立左右子节点。注意一共需要2N个节点来建立线段树。

线段树是一种二叉树结构,线段树上每个节点对应一个区间[L,R],节点的左儿子对应[L,Mid],右儿子对应[Mid+1,R]。

线段树单点修改

从根开始向下递归,找到包含这个点的所有区间,然后修改对应区间的统计值。

线段树区间查询

查询的时候将区间作为参数传入

如果查询区间是当前区间的,那么返回当前节点的统计值,如果查询区间是当前区间的一个子区间,根据将查询区间按情况递归进入左儿子,或者右儿子或者两边。这样可以把一个查询区间拆成已有的不超过2log n个区间。

线段树是一种解决区间修改与区间查询的数据结构,树状数组是一种简单高效的解决单点修改与前缀查询的数据结构,也就是说,树状数组能实现的功能,线段树都可以,但是线段树通常比树状数组慢一倍时间,代码长三倍。

RMQ问题,又称区间最值问题

ST表的作用:在O(nlogn)的时间内预处理完后,可在O(1)的时间查询区间最值。

碰到题目不会做,先写个模拟压压惊。

枚举的思想是不断地猜测,从所有可能的集合中一一尝试,然后再判断是否符合题目的条件。

单独提到枚举时我们往往认为这是一个暴力做法,但事实上并非如此,恰当的枚举往往会是解题的关键步骤。

模拟就是用计算机来模拟题目中要求的操作。

模拟题目通常具有码量大、操作多、思路繁复的特点。由于它码量大,经常会出现难以查错的情况,如果在考试中写错是相当浪费时间的。

做模拟题的步骤:

  • 先看懂题意,过一下样例;

  • 在动手写代码之前,在草纸上尽可能地写好要实现的流程;

  • 在代码中,尽量把每个部分模块化,写成函数等;

  • 对于一些可能重复用到的概念,可以统一转化,方便处理;

  • 调试时分块调试。模块化的好处就是可以方便的单独调某一部分;

  • 写代码的时候一定要思路清晰,不要想到什么写什么,要按照落在纸上的步骤写。

二分定义:在一个单调的有限数列上快速查找某一特定值的方法。

深度优先搜索。DFS 顾名思义就是在搜索树中优先搜索向深处延伸。简单来说就是“有路则走,无路回头”,总结为一个字:“莽”!

树是什么?

  • N个点,N-1条边的连通图。或者说,没有环的连通图。

  • 有根树,无根树

  • 树根,树上节点的父亲、儿子、祖先、后代、兄弟

  • 一个节点的深度定义为到根节点的距离

如何存储一棵树?

使用Vector[i]存储与节点i相邻的点的编号(稀疏图的存储方式)

如何遍历一棵树?

从树根开始,DFS递归遍历,每次遍历记录父亲是谁,避免死循环。

LCA问题的解法:

  • 通过欧拉遍历序(ETT)转化为区间最值(RMQ)问题。

  • 树上倍增法

如何生成一棵树的欧拉遍历序?

从根节点开始遍历,每次到达或者返回一个节点,将这个节点的编号放入序列末尾。

并查集实际维护的内容,可以看做是对集合的维护,且支持合并集合。

并查集的维护思路是,将每个集合做成一颗树型,用树的根作为集合的标志。那么,判断两点是否在一个集合内,只要找到两点所在树的树根,判断是否相同即可。合并两个集合时,让一颗树的树根父亲设为另一颗树的树根即可。用这样的结构即可维护点与点间连通性判定,但是,显然最坏这样复杂度会达到O(n^2)。

动态规划组成:有限状态,状态值函数,状态转移方程

状态就是能够恰好表达当前需要的信息的一组数据。

动规和搜索都是求解状态值函数的方法,一个递推、一个递归,一个重复值只算一次,一个重复值可能算多次,只要能搜就能动规,只要能动规也能搜索

通常,我们通过拓扑序遍历所有状态来逐个计算状态值函数。

状态转移方程需要满足如下条件:

  • 除了初始状态以外,每个状态都可以通过其他状态计算得出

  • 依赖关系不能成环(成环了,该按照什么顺序算???)

搜索的时间复杂度是指数界别的,而记忆化搜索比较快(可能快于动态规划)。

区间DP一般解决一些区间上的问题,往往和序列DP较难区分,如果一道题序列DP无法处理,可以考虑区间DP。通常dp[i][j] 表示区间[i,j]的最优值是多少,然后根据枚举分界点来转移。

环套树DP,通过断掉一条边变成普通树上DP

区间DP特点:n一般都很小,一般只有50-2000。

树形DP分类:

  • O(n)的树上递推(DFS)

  • 以子树为单位的转移(即dp[i]表示子树i的最优解)

cout换行时一定要用"\n",不要用endl,因为endl比"\n"要慢5-6倍。

当求多源最短路时,用 Floyd;当求单元最短路且有负数权值时,用 SPFA;当求单源最短路1且无负数边权时,用 Dijkstra 带堆优化的版本。

边上路径和最少的生成树称为最小生成树。

如何判断一个数是不是生成树?

看这个数连不连通。

强联通分量:

  • 解释:有向图中,每个点之间都能互相到达的的子图。

  • 本质:在有向图上找环。

次小生成树:

  • 第二小的生成树。

  • 删掉一条边,再加上一条边,使得差值尽量小,并且要是一个树。

  • 如果一条边在最小生成树上,我们就叫他树边,如果不在最小生成树上就叫他非树边。

  • 删掉一条树边,加上一条非树边。

  • 倍增 LCA 询问环上最大的值(章鱼图)。

SPFA本质上是 Bellman_ford 的优化。

  • 简要思路

维护一个队列,表示可能改变其他点最短路的点。不断向队列中加入可能改变其他点的最短路,然后再把新的点加入队列中,直至队列为空。

单源最短路Dijkstra

限制:边的权值必须都是正数。

  • 简要思路

每次选取 dist 值最小的值,也就是选取已经求出最短路的点(因为边的权值都是正数,所以它当前是最小值,那后面也不会有),然后对其进行松弛操作(用自己的最短路去更新其他点的最短路)。

判断二分图:

  • 简要思路

染色法:把一个未染色的点染色为1,然后一层一层向外染色。如果一条边连接的两个点的颜色一样,就说明不是二分图。注意要不断地循环找未染色的点,因为不保证连通。

二分图:

  • 把无向图的所有的点分为两个部分,第一部分的点连接的一定是第二部分的点,第二部分的点连接的一定是第一部分的点。也就是说一条边一定是连接第一部分和第二部分的点。不要求连通。

  • 树和森林就是二分图。在树中,深度为奇数的为第一部分,深度为偶数的为第二部分。

  • 存在奇环(奇数的环)的不是二分图,没有奇环的就是二分图。同样,所有的二分图也一定没有奇环。

二叉搜索树基本实现

点击查看代码
const int L=0,R=1;//L 左儿子,R 右儿子
struct node{//一个树上节点
	int son[2];//记录两个儿子的下标,分别对应于 son[L],son[R]
	int val;//这个节点储存的值
}a[MAXN];
int cnt;//用于分配节点编号

滚动数组代码

点击查看代码
//滚动数组代码 
//时间复杂度:O(nm)
#include<bits/stdc++.h>
using namespace std;
int f[maxn][maxn],v[maxn],w[maxn],m,n;//f[i][j] 代表前 i 个物品已经考虑完,用掉了 j 的体积所能获得的最大价值
signed main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>v[i]>>w[i];//读入体积和价值
    } 
	for(int i=0;i<=n;i++)
	{
		int p=(i&1);//p 代表 i 的奇偶性
		int q=p^1;//q 代表 i+1 的奇偶性
		memset(f[q],0,sizeof(f[q]));
		for(int j=0;j<=m;j++)
		{
			f[q][j]=max(f[q][j],f[p][j]);//不选
			f[q][h+v[i+1]]=max(f[q][h+v[i+1]],f[p][j]+w[i+1]); 
		}
	}
	int ans=0;
	for(int i=0;i<=m;i++)
	{
		ans=max(ans,f[n&1][i]);
    }
	cout<<ans<<endl;//cout<<f[n][m]<<endl;
}

有限背包DP代码

点击查看代码
//有限背包DP代码 
//时间复杂度:O(nm^2)
#include<bits/stdc++.h>
using namespace std;
int f[maxn][maxn],v[maxn],w[maxn],z[maxn],m,n;//f[i][j] 代表前 i 个物品已经考虑完,用掉了 j 的体积所能获得的最大价值
signed main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>v[i]>>w[i]>>z[i];//读入体积和、价值和个数 
    }
	for(int i=0;i<=n;i++)
	{
		for(int j=0;j<=m;j++)//要求状态f[i][j] 用别人去求自己 
		{
			for(int k=0;k*v[i]<=j&&k<]z[i];k++)//考虑第 i 种物品选 k 个 
			{
				f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]); 
		    }
	    }
    }
	int ans=0;
	for(int i=0;i<=m;i++)
	{
		ans=max(ans,f[n][i]);
    }
	cout<<ans<<endl;//cout<<f[n][m]<<endl;
}

区间DP代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int f[maxn][maxn],n,a[maxn],sum[maxn];
signed main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		sum[i]=sum[i-1]+a[i];
	}
	memset(f,0x3f,sizeof(f));
	for(int i=1;i<=n;i++)
	{
		f[i][i]=0;
    }
	for(int len=1;len<=n;len++)//当前要处理长度为 len 的区间
	{ 
		for(int l=1,r=len;r<=n;l++,r++)
		{
			for(int k=l;k<r;k++)
			{
				f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+sum[r]-sum[l-1]);
            }
        }
    }
	cout<<f[1][n]<<endl;
} 

树形DP代码

点击查看代码
//树形DP代码 
#include <bits/stdc++.h>
using namespace std;
int n,f[maxn],z[maxn];//f[i]代表以i为根的子树的大小 
void dfs(int p,int f)//代表当前要dp p点的值p的父亲为f 
{
	for(int i=0;i<z[p].size();i++)
	{
		int q=z[p][i];
		if(q!=f)
		{
			dfs(q,p);//dp儿子节点的值 
		}
	}
	f[p]=1;
	for(int i=0;i<z[p].size();i++)
	{
		int q=z[p][i];//从p到q的边 
		if(q!=f)
		{
			f[p]+=f[q];
		}
	}
}
int main()
{
	cin>>n;
	for(int i=1;i<n;i++)
	{
		int s,e;
		cin>>s>>e;
		add_edge(s,e);
		add_edge(e,s);
	}
	dfs(1,0);
	return 0;
}

求树上路径总长度和

点击查看代码
//求树上路径总长度和代码
#include <bits/stdc++.h>
using namespace std;
int n,f[maxn],ans,z[maxn];//f[i]代表以i为根的子树的大小 
void dfs(int p,int f)//代表当前要dp p点的值p的父亲为f 
{
	for(int i=0;i<z[p].size();i++)
	{
		int q=z[p][i];
		if(q!=f)
		{
			dfs(q,p);//dp儿子节点的值 
		}
	}
	f[p]=1;
	for(int i=0;i<z[p].size();i++)
	{
		int q=z[p][i];//从p到q的边 
		if(q!=f)
		{
			f[p]+=f[q];
		}
	}
	ans+=2*f[p]*(n-f[p]);
}
int main()
{
	cin>>n;
	for(int i=1;i<n;i++)
	{
		int s,e;
		cin>>s>>e;
		add_edge(s,e);
		add_edge(e,s);
	}
	dfs(1,0);
	return 0;
}

求树的直径代码

点击查看代码
//求树的直径代码
#include <bits/stdc++.h>
using namespace std;
int n,f[maxn][2],z[maxn];//f[i][1]代表以i为根向下最长是多少, f[i][2]代表以i为根向下次长是多少 
void dfs(int p,int f)//代表当前要dp p点的值p的父亲为f 
{
	for(int i=0;i<z[p].size();i++)
	{
		int q=z[p][i].first;
		if(q!=f)
		{
			dfs(q,p);//dp儿子节点的值 
		}
	}
	for(int i=0;i<z[p].size();i++)
	{
		int q=z[p][i].first;
		int d=z[p][i].second;
		if(q!=f)
		{
			int x=d+f[q][0]; 
			if(x>f[p][0])
			{
				f[p][1]=f[p][0];
				f[p][0]=x;
			}
			else if(x>f[p][1])
			{
				f[p][1]=x;
			}
		}
	}
	f[p]=1;
	for(int i=0;i<z[p].size();i++)
	{
		int q=z[p][i];//从p到q的边 
		if(q!=f)
		{
			f[p]+=f[q];
		}
	}
}
int main()
{
	cin>>n;
	for(int i=1;i<n;i++)
	{
		int s,e,d;
		cin>>s>>e>>d;
		add_edge(s,e,d);
		add_edge(e,s,d);
	}
	dfs(1,0);
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		ans=max(ans,f[i][0]+f[i][1]);
	} 
	cout<<ans;
	return 0;
}

询问树的最大独立集代码

点击查看代码
//询问树的最大独立集代码
//翻译:在树上选出尽可能多的点,使得点与点之间都互不相邻,问最多选多少个点。 
#include<bits/stdc++.h>
using namespace std;
int n,s,e,f[maxn][2];//f[i][0] 代表以 i 为根的子树 i 没选的情况下最多选几个点,f[i][1] 代表以 i 为根的子树 i 选了的情况下最多选几个点
void dfs(int p,int f)//当前要 DP p点的值,其中 p 的父亲为 f 
{
	for(int i=0;i<z[p].size();i++)
	{
		int q=z[p][i];
		if(q!=f)dfs(q,p); 
	}
	f[p][0]=1;
	f[p][1]=1;
	for(int i=0;i<z[p].size();i++)
	{
		int q=z[p][i];//从 p 到 q 的边
		if(q!=f)
		{
			f[p][1]+=f[q][0];
			f[p][0]+=max(f[q][1],f[q][0]);
		}
	}
} 
signed main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int s,e,d;
		add_edge(s,e,d);
		add_edge(e,s,d);
	}
	dfs(1,0);
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		ans=max(ans,f[i][0]+f[i][1])
    }
	cout<<ans<<endl;
} 

数位DP代码 求l~r中一共有多少个数

点击查看代码
//数位DP代码  求l~r中一共有多少个数 
#include <bits/stdc++.h>
using namespace std;
int l,r,f[30][2],x[maxn];//f[i][j]代表已经把yn~yi填好 j=0代表yn~yi<xn~xi否则等于的情况下 
int get(int x_)//求0~x_有多少个数
{
	int n=0;
	while(x_!=0)
	{
		n++;
		x[n]=x_%10;
		x_=x_/10;
	}
	memset(f,0,sizeof(f));
	f[n+1][1]=1;
	for(int i=n;i>=1;i--)//当前要填yi 
	{
		for(int j=0;j<2;j++)
		{
			int up=9;
			if(j==1)
			{
				up=x[i];
			}
			for(int k=0;k<=up;k++)
			{
				f[i][(j==1)&&(k==up)]+=f[i+1][j];
			}
		}
	} 
	return f[1][0]+f[1][1];
} 
signed main()
{
	cin>>l>>r;
	cout<<get(r)-get(l-1)<<endl;
	return 0;
}

数位DP代码 求l~r中所有数的数位之和

点击查看代码
//数位DP代码 求l~r中所有数的数位之和
//翻译:把l~r每个数各个数位上的数相加 
#include <bits/stdc++.h>
using namespace std;
int l,r,f[30][2],x[maxn],g[30][2];//f[i][j]代表已经把yn~yi填好 j=0代表yn~yi<xn~xi否则等于的情况下有多少种可能性 
int get(int x_)//求0~x_有多少个数
{
	int n=0;
	while(x_!=0)
	{
		n++;
		x[n]=x_%10;
		x_=x_/10;
	}
	memset(f,0,sizeof(f));
	f[n+1][1]=1;
	g[n+1][1]=0;
	for(int i=n;i>=1;i--)//当前要填yi 
	{
		for(int j=0;j<2;j++)
		{
			int up=9;
			if(j==1)
			{
				up=x[i];
			}
			for(int k=0;k<=up;k++)
			{
				f[i][(j==1)&&(k==up)]+=f[i+1][j];
				g[i][(j==1)&&(k==up)]+=g[i+1][j]+k*f[i+1][j];
			}
		}
	} 
	return g[1][0]+g[1][1];
} 
signed main()
{
	cin>>l>>r;
	cout<<get(r)-get(l-1)<<endl;
	return 0;
}

浮点数转整数代码

点击查看代码
//浮点数转整数代码
#include <bits/stdc++.h>
using namespace std;
double a;
int main()
{
    cin>>a;
    cout<<(long long)a;
    return 0;
}

加减乘取模代码

点击查看代码
//加减乘取模代码
#include<bits/stdc++.h>
using namespace std;
signed main(){
	//加法 
	x=(a+b)%p;
	x=(0ll+a+b+c)%p;
	x=((a+b)%p+c)%p; 
	
	//减法 
	x=((a-b)%p+p)%p;
	
	//乘法 
	x=1ll*a*b%p;
	x=1ll*a*b%p*c%p;
}

manacher代码 找最长的回文子串,问最长的长度是多少

点击查看代码
//manacher代码 时间复杂度:O(n)
//找最长的回文子串,问最长的长度是多少
#include<bits/stdc++.h>
using namespace std;
int f[maxn],n;//f[i] 代表以 i 为中心的最长回文子串的 右端点 - i
char s[maxn];
void Manacher()
{
	f[1]=0;
	int nowmid=1;//nowmid 当前右端点最靠右的回文子串的中心
	int nowr=1;//nowr 当前右端点最靠右的回文子串的右端点
	for(int i=2;i<=n;i++)//要算 f[i]
	{
		//抄答案
		if(i<=nowr)
		{
			f[i]=min(f[2*nowmid-i],nowr-i);
		}
		//暴力向左右扩展
		while(true)
		{
			int pl=i-f[i]-1;
			int pr=i+f[i]+1;
			if(pl>=1&&pr<=n&&s[pl]==s[pr])f[i]++;
			else break;
		}
		//更新右端点最靠右的回文子串
		if(i+f[i]>nowr)
		{
			nowmid=i,nowr=i+f[i]; 
		}
	} 
}
signed main()
{
	cin>>s+1;
	n=strlen(s+1); 
	for(int i=n;i>=1;i--)
	{
		s[i*2]=s[i];
	}
	for(int i=1;i<=2*n+1;i+=2)
	{
		s[i]='^';
	}	
	n=n*2+1;
	Manacher();
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		ans=max(ans,f[i]);
	}
	cout<<ans<<endl;
	return 0;
} 

判断一个数是不是质数代码

点击查看代码
//判断一个数是不是质数 
#include <bits/stdc++.h>
using namespace std;
int f;
bool is_prime(int n)//检查n是不是质数 
{
	if(n<2)
	{
		return false;
	}
	for(int i=2;i*i<=n;i++)
	{
		if(n%i==0)
		{
			return false;
		}
	}
	return true;
}
signed main()
{
	cin>>f;
	if(false)
	{
		cout<<"YES";
	}
	else
	{
		cout<<"NO";
	}
	return 0;
}

博弈论nim游戏代码

点击查看代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
    int T,i,s;
    cin>>T;
    while(T--) 
    {
        int n,x;
        cin>>n;
        for(i=1;i<=n;i++)
        {
            cin>>x;
            s=(i==1?x:s^x);
        }
        printf(s?"Yes\n":"No\n");
    } 
}

三维凸包代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=2010;
const double eps=1e-9;
int n,cnt,vis[N][N];
double ans;
double Rand(){return rand()/(double)RAND_MAX;}
double reps(){return (Rand()-0.5)*eps;}
struct Node
{
    double x,y,z;
    void shake(){x+=reps();y+=reps();z+=reps();}
    double len(){return sqrt(x*x+y*y+z*z);}
    Node operator - (Node A){return (Node){x-A.x,y-A.y,z-A.z};}
    Node operator * (Node A){return (Node){y*A.z-z*A.y,z*A.x-x*A.z,x*A.y-y*A.x};}
    double operator & (Node A){return x*A.x+y*A.y+z*A.z;}
}A[N];
struct Face
{
    int v[3];
    Node Normal() {return (A[v[1]]-A[v[0]])*(A[v[2]]-A[v[0]]);}
    double area() {return Normal().len()/2.0;}
}f[N],C[N];
int see(Face a,Node b){return ((b-A[a.v[0]])&a.Normal())>0;}
void Convex_3D()
{
    f[++cnt]=(Face){1,2,3};
    f[++cnt]=(Face){3,2,1};
    for(int i=4,cc=0;i<=n;i++)
    {
        for(int j=1,v;j<=cnt;j++)
        {
            if(!(v=see(f[j],A[i]))) 
                C[++cc]=f[j];
            for(int k=0;k<3;k++) 
                vis[f[j].v[k]][f[j].v[(k+1)%3]]=v;
        }
        for(int j=1;j<=cnt;j++)
            for(int k=0;k<3;k++)
            {
                int x=f[j].v[k],y=f[j].v[(k+1)%3];
                if(vis[x][y]&&!vis[y][x]) 
                    C[++cc]=(Face){x,y,i};
            }
        for(int j=1;j<=cc;j++) 
            f[j]=C[j];
        cnt=cc,cc=0;
    }
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) 
        cin>>A[i].x>>A[i].y>>A[i].z,A[i].shake();
    Convex_3D();
    for(int i=1;i<=cnt;i++) 
        ans+=f[i].area();
    printf("%.3f",ans);
}

模意义下的乘法逆元代码

点击查看代码
#include <bits/stdc++.h>
using namespace std;
long long n,p,inv[20000528];
signed main()
{
    scanf("%d %d",&n,&p);
    inv[1]=1;
    printf("%ld\n",inv[1]);
    for(int i=2;i<=n;i++)
    {
        inv[i]=(p-p/i)*inv[p%i]%p;
        printf("%ld\n",inv[i]);
    }
    return 0;
}

中国剩余定理(CRT)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
long long a[5211314], b[5211314], n;
void Exgcd(long long a, long long b, long long &x, long long &y)
{
	if (b == 0) 
	{
		x = 1;
		y = 0;
		return;
	}
	long long x1, y1;
	Exgcd(b, a % b, x1, y1);
	x = y1;
	y = x1 - a / b * y1;
	return; 
}
long long CRT(long long m[], long long r[]) 
{
	long long M = 1, ans = 0;
	for (int i = 1; i <= n; ++ i) 
	{
		M *= m[i];
	}
	for (int i = 1; i  <= n; ++ i)
	{
		long long c = M / m[i], x, y;
		Exgcd(c, m[i], x, y);
		ans = (ans + r[i] * c * x % M) % M;
	}
	return (ans + M) % M;
} 
int main() 
{
	scanf("%lld", &n);
	for (int i = 1; i <= n;i++) 
	{
		scanf("%lld%lld", a + i, b + i);
	}
	printf("%lld\n", CRT(a, b));
	return 0;
}

最小生成树kruskal代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
long long f[500007],n,m,num,cnt,ans;
struct Edge{
    long long u,v,w ;
}e[500007];
long long find(long long k){return (f[k]==k)?k:f[k]=find(f[k]);}
bool cmp(Edge a, Edge b){return a.w<b.w;}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
        cin>>e[i].u>>e[i].v>>e[i].w;
    for(int i=1;i<=n;i++)
        f[i]=i;
    sort(e+1,e+m+1,cmp);
    for(int i=0;i<=m;i++)
    {
        if(find(e[i].u)==find(e[i].v))
            continue;
        f[find(e[i].u)]=find(e[i].v);
        ans+=e[i].w;
        if(++num==n-1) break;
    }
    cout<<ans<<endl;
	return 0;
}

最小生成树prim代码

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define INF INT_MAX
using namespace std;
const int M=3005;
const int N=2005;
int n,m,tot,ans;
int head[N],dist[N],vis[N]; 
struct node{
    int to,next,w;
}edge[M<<1];
void addedge(int x, int y, int z)
{
    tot++;
    edge[tot].to = y;
    edge[tot].w = z;
    edge[tot].next = head[x];
    head[x] = tot;
}
void Prim()
{
    for(int i = head[1]; i; i = edge[i].next)
        dist[edge[i].to] = min(dist[edge[i].to], edge[i].w); 
    int u = 1;
    for(int i = 1; i < n; i++)
    {
        int minn=INF; 
        vis[u]=true;
        for(int j = 1; j <= n; j++)
        {
            if(!vis[j] && dist[j] < minn)
            {
                u = j;
                minn = dist[j];
            }
        }
        ans += minn;
        for(int k = head[u]; k; k = edge[k].next)
        {
            int v = edge[k].to; 
            if(dist[v] > edge[k].w && !vis[v])
                dist[v] = edge[k].w;
        } 
    }
}
void Init()
{
    for(int i=1;i<=n;i++)
        dist[i]=INF;
    dist[1]=0;
    return;
}
int main()
{
    cin>>n>>m;
    while(m--)
    {
        int x, y, z;
        cin>>x>>y>>z;
        addedge(x,y,z);
        addedge(y,x,z);
    }
    Init();
    Prim();
    cout<<ans<<endl;
    return 0;
} 

字符串哈希代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
ull base=131,a[10010];
char s[10010];
int n,ans=1;
const ull mod=212370440130137957ll;
ull hashs(char s[])
{
    int len=strlen(s);
    ull ans=0;
    for(int i=0;i<len;i++)
        ans=(ans*base+(ull)s[i])%mod;
    return ans;
}
main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s);
        a[i]=hashs(s);
    }
    sort(a+1,a+n+1);
    for(int i=2;i<=n;i++)
        if(a[i]!=a[i-1])
            ans++;
    printf("%d\n",ans);
}

快速排序代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,a[1000001];
void quicksort(int l, int r)
{
    int mid=a[(l+r)/2];
    int i=l,j=r;
    while(i<=j)
    {
        while(a[i]<mid) i++;
        while(a[j]>mid) j--;
        if(i<=j)
        {
            swap(a[i],a[j]);
            i++;
            j--;
        }
    }
    if(l<j) 
        quicksort(l,j);
    if(i<r) 
        quicksort(i,r);
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) 
        cin>>a[i];
    quicksort(1,n);
    for(int i=1;i<=n;i++) 
        cout<<a[i]<<" ";
}

线性筛代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
bool isprime[100000010];
int prime[6000010],n,q,k,cnt;
void getprime(int n)
{
    memset(isprime,1,sizeof(isprime));
    isprime[1]=0;
    for(int i=1;i<=n;i++)
    {
        if(isprime[i])
            prime[++cnt]=i;
        for(int j=1;j<=cnt&&i*prime[j]<=n;j++)
        {
            isprime[i*prime[j]]=0;
            if(i%prime[j]==0)
                break;
        }
    }
}
int main()
{
    cin>>n>>q;
    getprime(n);
    while(q--)
    {
        cin>>k;
        cout<<prime[k]<<endl;
    }
}

小根堆代码

点击查看代码
#include<bits/stdc++.h>
using namespace std; 
priority_queue<int,vector<int>,greater<int> >q;
int n,x;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>x;
        if(x==1) 
        {
            cin>>x;
            q.push(x);
        }
        else 
        if(x==2) 
            cout<<q.top()<<endl;
        else 
            q.pop();       
    }   
} 

并查集代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,m,s,ans,f[10010],p1,p2,p3;
int find(int k)
{
    if(f[k]==k)
        return k;
    return f[k]=find(f[k]);
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        f[i]=i;
    for(int i=1;i<=m;i++)
    {
        cin>>p1>>p2>>p3;
        if(p1==1)
            f[find(p2)]=find(p3);
        else
            cout<<(find(p2)==find(p3)?"Y":"N")<<endl;
    }
    return 0;
}

有理数取余代码

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int mod=19260817;
int a,b;
int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch=='-') 
		{
		    f=-1;
		}
		ch=getchar();
	}
	while(ch>='0' && ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^48);
		x=x%mod;
		ch=getchar();
	}
	return x*f;
}
int exgcd(int a,int b,int &x,int &y)
{
	if(!b)
	{
		x=1,y=0;
		return a;
	}
	int d=exgcd(b,a%b,x,y);
	int temp=x;
	x=y;
	y=temp-(a/b)*y;
	return d;
}
int main()
{
	a=read();
	b=read();
	if(b==0)
	{
		puts("Angry");
		return 0;
	}
	int x,y;
	int d=exgcd(b,mod,x,y);
	x=(x%mod+mod)%mod;
	printf("%lld\n",a*(long long )x %mod);
	return 0;	
	return 0;
}

手写随机堆代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int seed=2322333;
bool random_bool(){
	seed = seed * 997 % 100007;
	return seed & 32;      // 取出二进制从低到高第 6 位 
}
struct node{
	int val;
	int lson, rson;  // int son[2]; son[L] son[R];   
};
node a[100005];
int cnt; // 根节点是1号点 
void insert(int k, int val){ // 节点k在的树,插入 val 
	if(val > a[k].val)	// 进来的val 更大,直接篡位 
		swap(val, a[k].val);	// 旧王退位 
	if(a[k].lson == 0){	// 左儿子这边一个节点都没有 
		a[k].lson = ++cnt;  // 安置在这里,新建一个点 
		a[cnt].val = val;
	}else if(a[k].rson == 0){ // 如果左边不空,右边空,那就去右边 
		a[k].rson = ++cnt;
		a[cnt].val = val;
	}else if(random_bool()) // 不然的话,随机一边递归下去 
		insert(a[k].lson, val);
	else
		insert(a[k].rson, val);
}
bool is_leaf(int k){
	return a[k].lson == 0 && a[k].rson == 0;
}
void remove(int k){ // 把这个节点的值删掉
	if(a[a[k].lson].val > a[a[k].rson].val){
		a[k].val = a[a[k].lson].val; // 把左儿子拿过来替补 
		if (!is_leaf(a[k].lson))
			remove(a[k].lson);
		else
			a[k].lson = 0;
	}else{
		a[k].val = a[a[k].rson].val;  // 把右儿子拿过来替补  
		if (!is_leaf(a[k].rson))
			remove(a[k].rson);
		else
			a[k].rson = 0;
	}
}

int root, ele_cnt;
void push(int val){ // 堆里插入一个值为val的元素 
	ele_cnt++;	// 给这个新的元素分配一个点 
	insert(root, val);
}
void pop(){
	ele_cnt--;
	remove(root);
} 
int top(){
	return a[root].val;
}
bool empty(){
	return ele_cnt == 0;
}
int main(){
	a[0].val = -999999999;
	a[1].val = -999999999;
	root=cnt=1;
	push(233);
	push(666);
	push(-3);
	push(99);
	
	//访问队列首元素,注意这里不是像队列一样使用front和back来访问首元素和尾元素
	cout << top() <<endl;
	
	//删除首元素
	pop();

	cout << top() <<endl;
	
	//判断队列是否为空
	if(!empty()) cout << "队列不为空" <<endl;

	//输出剩下元素
	while(!empty()){
		cout << top() << " ";
		pop();
	}
	return 0;
}

A+B A-B A*B A/B A%B高精度代码

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#ifndef _INTEGER_HPP_
#define _INTEGER_HPP_
namespace PsephurusGladius
{
    namespace integer
    {
        const int Max_Integer_Length=1e4;
        char char_array_temp[Max_Integer_Length];
        class Integer{
            private:
                int digit[Max_Integer_Length],count;
                short signum;
            public:
                Integer(void);
                Integer(const Integer &target);
                Integer(const long long &target);
                Integer(const char *target);
                operator char*(void);
                void zero(void);
                friend std::istream& operator >>(std::istream &Cin,Integer &target);
                friend std::ostream& operator <<(std::ostream &Cout,const Integer &target);
                Integer absolute_value(void)const;
                Integer opposite_number(void)const;
                Integer operator -(void)const;
                friend bool operator <(const Integer &target1,const Integer &target2);
                friend bool operator >(const Integer &target1,const Integer &target2);
                friend bool operator <=(const Integer &target1,const Integer &target2);
                friend bool operator >=(const Integer &target1,const Integer &target2);
                friend bool operator ==(const Integer &target1,const Integer &target2);
                friend bool operator !=(const Integer &target1,const Integer &target2);
                friend Integer operator +(const Integer &target1,const Integer &target2);
                friend Integer operator -(const Integer &target1,const Integer &target2);
                friend Integer operator *(const Integer &target1,const Integer &target2);
                friend Integer operator /(const Integer &target1,const Integer &target2);
                friend Integer operator %(const Integer &target1,const Integer &target2);
                Integer& operator ++(void);
                Integer operator ++(int);
                Integer& operator --(void);
                Integer operator --(int);
                Integer operator +=(const Integer &target);
                Integer operator -=(const Integer &target);
                Integer operator *=(const Integer &target);
                Integer operator /=(const Integer &target);
                Integer operator %=(const Integer &target);
        };
        inline Integer::Integer(void):count(0),signum(0){
            memset(digit,0,sizeof(digit));
        }
        inline Integer::Integer(const Integer &target):count(target.count),signum(target.signum){
            memcpy(digit,target.digit,sizeof(digit));
        }
        inline Integer::Integer(const long long &target){
            memset(digit,0,sizeof(digit));
            signum=target<0?-1:(target>0?1:0);
            count=-1;
            long long temp=target;
            do{
                digit[++count]=temp%10000;
                temp/=10000;
            }
            while(temp);
        }
        inline Integer::Integer(const char *target){
            memset(digit,0,sizeof(digit));
            int start=0,len=strlen(target);
            if(target[0]=='-'&&(target[1]!='0'||len!=2)){
                signum=-1;
                ++start;
            }
            else if(target[0]!='0'||len!=1)signum=1;
            else signum=0;
            count=(len-start-1)/4;
            for(int i=start,sum=0;i<len;++i)
            {
                sum=sum*10+target[i]-'0';
                if(!((len-i-1)%4))
                {
                    digit[count-(i-start)/4]=sum;
                    sum=0;
                }
            }
            while(count>0&&!digit[count])
                --count;
        }
        inline Integer::operator char*(void)
        {
            memset(char_array_temp,0,sizeof(char_array_temp));
            for(int i=count,len=0;i>-1;--i)
            {
                if(i==count)
                {
                    len+=sprintf(char_array_temp+len,"%d",digit[i]);
                    continue;
                }
                len+=sprintf(char_array_temp+len,"%04d",digit[i]);
            }
            return char_array_temp;
        }
        inline void Integer::zero(void)
        {
            memset(digit,0,sizeof(digit));
            count=signum=0;
        }
        inline std::istream& operator >>(std::istream &Cin,Integer &target)
        {
            scanf("%s",char_array_temp);
            target=Integer(char_array_temp);
            return Cin;
        }
        inline std::ostream& operator <<(std::ostream &Cout,const Integer &target)
        {
            if(target.signum==-1)
                printf("-");
            printf("%d",target.digit[target.count]);
            for(int i=target.count-1;i>-1;--i)
                printf("%04d",target.digit[i]);
            return Cout;
        }
        inline Integer Integer::absolute_value(void)const
        {
            if(!count&&!signum)
                return *this;
            else
            {
                Integer result=*this;
                result.signum=1;
                return result;
            }
        }
        inline Integer Integer::opposite_number(void)const
        {
            Integer result=*this;
            result.signum*=-1;
            return result;
        }
        Integer Integer::operator -(void)const
        {
            return opposite_number();
        }
        inline bool operator <(const Integer &target1,const Integer &target2)
        {
             if(target1.signum!=target2.signum)
                 return target1.signum<target2.signum;
             if(target1.signum==-1)
                 return target2.absolute_value()<target1.absolute_value();
            if(target1.count!=target2.count)
                 return target1.count<target2.count;
             for(int i=target1.count;i>-1;--i)
                 if(target1.digit[i]!=target2.digit[i])
                     return target1.digit[i]<target2.digit[i];
             return false;
        }
        inline bool operator >(const Integer &target1,const Integer &target2)
        {
            return !(target1<target2)&&!(target1==target2);
        }
        inline bool operator ==(const Integer &target1,const Integer &target2)
        {
            if(target1.signum!=target2.signum||target1.count!=target2.count)
                 return false;
             for(int i=target1.count;i>-1;--i)
                 if(target1.digit[i]!=target2.digit[i])
                     return false;
             return true;
        }
        inline bool operator <=(const Integer &target1,const Integer &target2)
        {
            return target1<target2||target1==target2;
        }
        inline bool operator >=(const Integer &target1,const Integer &target2)
        {
            return !(target1<target2);
        }
        inline bool operator !=(const Integer &target1,const Integer &target2)
        {
            return !(target1==target2);
        }
        inline Integer operator +(const Integer &target1,const Integer &target2)
        {
            if(target1.signum!=target2.signum)
                if(!target1.signum||!target2.signum)
                    return target1.signum?target1:target2;
                else return target1.signum<target2.signum?target2-target1.absolute_value():target1-target2.absolute_value();
            Integer result;
            result.count=target1.count<target2.count?target2.count:target1.count;
            result.signum=target1.signum;
            for(int i=0;i<=result.count;++i)
            {
                result.digit[i]+=target1.digit[i]+target2.digit[i];
                result.digit[i+1]=result.digit[i]/10000;
                result.digit[i]%=10000;
            }
            if(result.digit[result.count+1])
                ++result.count;
            return result;
        }
        inline Integer operator -(const Integer &target1,const Integer &target2)
        {
            if(target1.signum!=target2.signum)
                if(!target1.signum||!target2.signum)
                    return target1.signum?target1:target2.opposite_number();
                else return target1.signum<target2.signum?(target1.absolute_value()+target2).opposite_number():target1+target2.absolute_value();
            if(target1<target2)
                return (target2-target1).opposite_number();
            Integer result;
            if(target1==target2)
                return result;
            result.count=target1.count;
            result.signum=1;
            for(int i=0;i<=result.count;++i)
            {
                result.digit[i]+=target1.digit[i]-target2.digit[i];
                if(result.digit[i]<0)
                {
                    --result.digit[i+1];
                    result.digit[i]+=10000;
                }
            }
            while(result.count>0&&!result.digit[result.count])
                --result.count;
            return result;
        }
        inline Integer operator *(const Integer &target1,const Integer &target2)
        {
            Integer result;
            if(!target1.signum&&!target2.signum)
                return result;
            result.signum=target1.signum*target2.signum;
            result.count=target1.count+target2.count+1;
            for(int i=0;i<=target1.count;++i)
                for(int j=0;j<=target2.count;++j)
                {
                    result.digit[i+j]+=target1.digit[i]*target2.digit[j];
                    result.digit[i+j+1]+=result.digit[i+j]/10000;
                    result.digit[i+j]%=10000;
                }
            while(result.count>0&&!result.digit[result.count])
                --result.count;
            return result;
        }
        inline Integer operator /(const Integer &target1,const Integer &target2)
        {
            Integer result,temp,now;
            if(!target1.signum||target1.absolute_value()<target2.absolute_value())
                return result;
            if(!target2.signum)
                throw std::logic_error("divide by zero!");
            result.signum=target1.signum*target2.signum;
            result.count=target1.count;
            now.signum=1;
            for(int i=result.count;i>-1;--i)
            {
                for(int j=now.count;j>-1;--j)
                    now.digit[j+1]=now.digit[j];
                now.digit[0]=target1.digit[i];
                if(now.digit[now.count+1])
                    ++now.count;
                now.signum=1;
                if(now<target2)
                    continue;
                int left=0,right=9999;
                while(left<right)
                {
                    int mid=(left+right)/2;
                    if(target2*Integer(mid)<=now)
                        left=mid+1;
                    else
                        right=mid;
                }
                result.digit[i]=left-1;
                now-=Integer(left-1)*target2;
            }
            while(result.count>0&&!result.digit[result.count])
                --result.count;
            return result;
        }
        inline Integer operator %(const Integer &target1,const Integer &target2)
        {
            return target1-target1/target2*target2;
        }
        inline Integer& Integer::operator ++(void)
        {
            return *this=*this+Integer(1ll);
        }
        inline Integer Integer::operator ++(int)
        {
            Integer result=*this;
            ++*this;
            return result;
        }
        inline Integer& Integer::operator --(void)
        {
            return *this=*this-Integer(1ll);
        }
        inline Integer Integer::operator --(int)
        {
            Integer result=*this;
            --*this;
            return result;
        }
        inline Integer Integer::operator +=(const Integer &target)
        {
            return *this=*this+target;
        }
        inline Integer Integer::operator -=(const Integer &target)
        {
            return *this=*this-target;
        }
        inline Integer Integer::operator *=(const Integer &target)
        {
            return *this=*this*target;
        }
        inline Integer Integer::operator /=(const Integer &target)
        {
            return *this=*this/target;
        }
        inline Integer Integer::operator %=(const Integer &target)
        {
            return *this=*this%target;
        }
    }
}
#endif
using namespace PsephurusGladius;
using namespace integer;
Integer a,b;
signed main(){
	cin>>a>>b;
	cout<<a+b<<endl<<a-b<<endl<<a*b<<endl<<a/b<<endl<<a%b;
	return 0;
}

倍增LCA代码

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=110; // 最多的点数 
const int maxm=210; // 最多的边数
int n;
vector<int> g[maxn]; // g[i] 存着与i相连的点 
void AddEdge(int u,int v) { // 添加一个(u,v)双向边 
	g[u].push_back(v);
	g[v].push_back(u); 
}
int fa[20][maxn],dep[maxn]; // fa[i][k] 表示k节点往上走 2的i次方步到哪个祖先
// dep 存的是节点深度 
void dfs(int x, int father){ // 树上遍历建立倍增表 
	fa[0][x] = father; // 记录一下 
	dep[x] = dep[father]+1; // 根节点深度为 1 
	for(int i=1;(1<<i)<=dep[x];i++) 
		fa[i][x]=fa[i-1][fa[i-1][x]];
	for(auto to: g[x]) //遍历自己的儿子
		if(to != father) // 别跑回父亲去了 
			dfs(to, x);
}
int lca(int x,int y) { 
	if(dep[x]<dep[y]) swap(x,y); // 先保证 x的深度比y的深度深 
	// 假设 dep[x] - dep[y] = 6 = 4 + 2
	// 6 的二进制是 0110,对应了 4 (0100) 和 2(0010) 
	for(int i=19;i>=0;i--) 
		if( (dep[x]-dep[y]) & (1<<i)) // 拿2的整数次幂凑出我们要走的距离
//		if( (dep[x]-dep[y]) >= (1<<i)) // 等效写法,能走就走 
			x=fa[i][x];
	if(x == y) return x; // 如果某一个人是另一个人的直接祖先,返回 
	for(int i=19;i>=0;i--) // 倍增找深度最浅不相同的祖先 
		if(fa[i][x] != fa[i][y]) 
			x=fa[i][x], y=fa[i][y];
	return fa[0][x]; // 返回某个的直接父亲就是最近公共祖先 
}
int main() {
	n=5;
	AddEdge(1,2);
	AddEdge(2,3);
	AddEdge(2,5);
	AddEdge(5,6);
	AddEdge(1,4);
	AddEdge(4,7);
	AddEdge(7,8);
	AddEdge(7,9);
	dfs(1,0);
	printf("%d\n",lca(3,9));
	return 0;
}

vector存图代码

点击查看代码
#include<vector>
#include<cstdio>
#include<iostream>
using namespace std;
vector<int> g[100005]; // g[i] 里面存着所有与 i 相连的点的编号 
int main(){
	vector<int> v; // 数组v
	v.push_back(1);
	v.push_back(1);
	v.push_back(4);
	v.push_back(1);
	v.push_back(1);
	v.push_back(4);
	printf("%d\n", v.size());
	printf("%d\n", v[5]);
	for(int i=0;i<v.size();i++)
		printf("%d\n", v[i]);
	for(auto i: v)
		printf("%d\n", i);
	return 0;
} 

ST表代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
inline int read(){
	int x=0,f=1; // x 表示我们读到值, f表示数的符号 
	char ch=getchar(); // getchar 是获得输入内容的下一个字符 
	while (!isdigit(ch)){
		if (ch=='-') f=-1; // 说明输入一个负数 
		ch=getchar(); // 不然的话下一个字符 
	}
	while (isdigit(ch)){
		x=x*10+(ch-'0'); // x=123, x=1234 = 123 * 10 + 4
		ch=getchar(); // 读下一个字符 
	}
	return x*f; // 数字乘上符号 
}
const int INF = 0x3f3f3f3f; // 大概是 10的9次方多一些  INF+INF < 2^31 
int n,m; // 假设我们序列长度为 n,一共有m个询问。 
int a[N]; // a是初始值序列 

//ST表 
int st[20][N]; // st[i][L] 表示从 L 开始长度为 2^i 的区间的最大值 
int logn[N]; // logn[i] 表示 2^logn[i] 次方不超过 i
// logn[1] = 0, logn[2] = 1, logn[3] = 1, logn[4] = 2, logn[5] = 2, logn[6]=2, logn[7]=2, logn[8]=3 
// logn[i] = logn[i/2] + 1 
void pre(){
	for(int i=2;i<=n+2;i++) logn[i]=logn[i>>1]+1; // 预处理一下logn数组 
	for(int i=1;i<=n;i++) // 初始化st 表第一行 st[0], 即长度为1的序列 
		st[0][i]=a[i];
	for(int i=1;(1<<i)<=n;i++) // (1<<i) = 2的i次方, 
		for(int j=1;j+(1<<i)-1<=n;j++){ // j 是区间起始位置, j+(1<<i)-1 是区间结尾 
			st[i][j]=max(st[i-1][j],st[i-1][j+(1<<(i-1))]);
			// 例如 i=2, j=3, st[2][3] 表示区间 [3,6] 
			// 那么就是 st[2][3] = max(st[1][3], st[1][5]); 
			// 其中st[1][3] 表示区间 [3, 4], st[1][5] 表示区间 [5, 6] 
		}
}
int getmax(int l,int r){ // 查询[l, r] 
	if(l>r) return -INF; //  
	int d=logn[r-l+1]; // 不超过区间长度的最大的2的整数次幂 
	return max(st[d][l],st[d][r-(1<<d)+1]); // l开始长度为2的d次方的,和结束于r的长度为2的d次方的 
}

int main(){
	n = read(), m = read();
	for(int i=1;i<=n;i++) a[i]=read();
	pre();
	for(int i=1;i<=m;i++){
		int l=read(), r=read();
		printf("%d\n", getmax(l,r));
	} 
	return 0;
}
posted @ 2023-10-01 17:02  zhuyucheng  阅读(65)  评论(1)    收藏  举报