模板大全

【永远置顶】万能程序模板

#include<bits/stdc++.h>
using namespace std;
//#define Inc
#ifdef Inc
#include<bits/extc++.h>
#include<windows.h>
#endif
#define Define
#ifdef Define
#define up(_name_,_leftbound_,_rightbound_) for(auto _name_=(_leftbound_);(_name_)<=(_rightbound_);++(_name_))
#define dn(_name_,_leftbound_,_rightbound_) for(auto _name_=(_leftbound_);(_name_)>=(_rightbound_);--(_name_))
#define For(_an_iterator_,_an_big_array_) for(auto _an_iterator_:_an_big_array_)
#define DEBUG cerr<<"---DEBUG---\n"<<__LINE__<<"\n-----------\n"
#define ll long long
#define ull unsigned long long
#define un unsigned
#define il inline
#define re register
#define i128 __int128
#define endl '\n'
#define db double
#define ld long double
#define Log(_shang_,_xia_) (log(_shang_)/log(_xia_))
#define _1 first
#define _2 second
#define mkp make_pair
#define pb(_Num_) push_back(_Num_)
#define pq priority_queue
#define pii pair<int,int>
#define to0(_an_array_) memset(_an_array_,0,sizeof(_an_array_))
#define toinf(_an_array_) memset(_an_array_,0x3f,sizeof(_an_array_))
#define qxx(_an_iterator_,_an_from_) for(auto _an_iterator_=head[_an_from_];_an_iterator_;_an_iterator_=e[_an_iterator_].nxt)
#define Ent cout<<endl
#define put(_an_num_) cout<<(_an_num_)<<endl 
constexpr int inf=0x3f3f3f3f;
constexpr int mod=1e9+7;
constexpr ll mod2=212370440130137957;
constexpr int base=1331;
il ll read(){
	ll x=0,f=1;char tmp=getchar();
	while(!isdigit(tmp)){if(tmp=='-') f=-1;tmp=getchar();}
	while(isdigit(tmp)){x=x*10+tmp-'0';tmp=getchar();}
	return x*f;
}
ll Pow(ll a,ll b,ll mod){
	ll ans=0;
	while(b){if(b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;}
	return b;
}
ll Hash(string s){
	ll ans1=0,ans2=0;
	For(ch,s){
		ans1+=(ans1*ans1%mod+Pow(ch,ch,mod1))%mod1;
		ans2+=(ans2*ans2%mod+Pow(ch,ch,mod2))%mod2;
	}
	ans1^=(ans1>>13);ans1^=(ans1<<4);ans1^=(ans1<<13);
	ans2^=(ans2>>5);ans2^=(ans2<<7);ans2^=(ans2<<4);
	return (ans1+ans2)%(ans1^ans2);
}
#endif
const int N=200005;
const int M=200005;
int n,m,k;

void init_(){
	
	return;
}

void Main(int cases){

	return;
}
/*
---INFORMATIONS---
TIME:<DATETIME>
PROBLEM:
CODE BY __CrossBow_EXE__ Luogu uid967841
CEXE好闪,拜谢CEXE。
*/
#define oneCase
signed main(int argc,char *argv[]){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	int T;
#ifdef oneCase
	T=1;
#else
	T=read();
#endif
	init_();
	up(i,1,T) Main(i);
	return 0;
}

数据结构模板

大根堆,一条大根堆

int heap[10005],num=0;//大根堆 
void in(int x){
	heap[++num]=x;
	int fa;
	int son=num;
	while(son/2){
		fa=son/2;
		if(heap[son]>heap[fa]) swap(heap[son],heap[fa]);
		else break;
		son=fa;
	}
}

int out(){
	int res=heap[1];
	heap[1]=heap[num--];
	int fa=1,son;
	while(fa*2<=num){
		son=fa*2;
		if(son+1<=num&&heap[son]<heap[son+1]) son++;
		if(heap[son]>heap[fa]) swap(heap[son],heap[fa]);
		else break;
		fa=son;
	}
	return res;
}

小根堆

int heap[10005],num=0;//小根堆 
void in(int x){
	heap[++num]=x;
	int fa;
	int son=num;
	while(son/2){
		fa=son/2;
		if(heap[son]<heap[fa]) swap(heap[son],heap[fa]);
		else break;
		son=fa;
	}
}

int out(){
	int res=heap[1];
	heap[1]=heap[num--];
	int fa=1,son;
	while(fa*2<=num){
		son=fa*2;
		if(son+1<=num&&heap[son]>heap[son+1]) son++;
		if(heap[son]<heap[fa]) swap(heap[son],heap[fa]);
		else break;
		fa=son;
	}
	return res;
}

单调栈

for(int i=1;i<=n;i++){
  while(!st.empty()&&a[st.top()]<a[i]) num[st.top()]=i,st.pop();
  st.push(i);
}

单调队列(滑动窗口)

head=0,tail=-1;
for(int i=1;i<=n;i++){
	while(head<=tail&&a[q[tail]]>=a[i]) tail--;//窗口最小值
	q[++tail]=i;
	while(q[head]<i-k+1) head++;
	if(i>=k) cout<<a[q[head]]<<' ';
}
cout<<endl;

ST表

输入

for(int i=1;i<=n;i++){
	cin>>a[i][0];
}

预处理

for(int j=1;j<20;j++){
	for(int i=1;i<=n;i++){
		a[i][j]=max(a[i][j-1],a[min(i+(1<<j-1),n)][j-1]);
	}
}

查询

while(m--){
	cin>>l>>r;
	int k=log2(r-l+1);
	cout<<max(a[l][k],a[r-(1<<k)+1][k])<<endl;
}

真神线段树

单点修改、求区间和

原题

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const int N=1000005;
int n,m,op,x,y;
int a[N];
struct node{
	int l,r,sum;//左右儿子 区间和 
}tr[N<<2];//共4*n个线段树节点 
void pushup(int u){//和向上传递 
	tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
	//和=左边和+右边和 
}
void build(int u,int l,int r){
	tr[u].l=l,tr[u].r=r;
	if(l==r){//如果到了叶子区间 
		tr[u].sum=a[l];//和直接就是a[l] 
		return;
	}
	int mid=(l+r)>>1;
	build(u<<1,l,mid);//建左边 
	build(u<<1|1,mid+1,r);//建右边
	pushup(u);//传递上去 
}
void modify(int u,int x,int k){
	if(tr[u].l==tr[u].r){//是叶子节点 
		tr[u].sum+=k;//直接修改就行 
		return;
	}
	//tr[u].l - tr[u].r
	int mid=(tr[u].l+tr[u].r)>>1;
	//tr[u].l - mid,mid+1 - tr[u].r
	if(x<=mid) modify(u<<1,x,k);//改左边 
	else modify(u<<1|1,x,k);//改右边 
	pushup(u);
}
int ask(int u,int l,int r){
	if(tr[u].l>=l&&tr[u].r<=r) return tr[u].sum;//包含在区间内,直接输出和
	int mid=(tr[u].l+tr[u].r)>>1,sum=0;
	if(mid>=l) sum+=ask(u<<1,l,r);//加左边 
	if(mid<r) sum+=ask(u<<1|1,l,r);//加右边 
	return sum;
}
int main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	build(1,1,n);//从1建到n 
	while(m--){
		cin>>op;
		if(op==1){
			cin>>x>>y;
			modify(1,x,y);//a[x]+=y 
		}else{
			cin>>x>>y;
			cout<<ask(1,x,y)<<endl;
		}
	}
	return 0;
}

区间修改、求区间和

原题

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define int long long
using namespace std;
const int N=100005;
int a[N];
int n,m,op,x,y,k;
struct node{
	int l,r,sum,lazy;
}tr[N<<2];
void pushup(int u){
	tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
void pushdown(int u){
	if(tr[u].lazy){//有懒标记才pushdown 
		tr[u<<1].sum+=(tr[u<<1].r-tr[u<<1].l+1)*tr[u].lazy;//区间和增加(区间元素个数)个懒标记 
		tr[u<<1|1].sum+=(tr[u<<1|1].r-tr[u<<1|1].l+1)*tr[u].lazy;
		tr[u<<1].lazy+=tr[u].lazy;//把懒标记传递给左右孩子 
		tr[u<<1|1].lazy+=tr[u].lazy;
		tr[u].lazy=0;//清空懒标记 
	}
}
void build(int u,int l,int r){
	tr[u].l=l,tr[u].r=r;
	if(l==r){
		tr[u].sum=a[l];
		tr[u].lazy=0;//懒标记初始化 
		return;
	}
	int mid=(l+r)>>1;
	build(u<<1,l,mid);
	build(u<<1|1,mid+1,r);
	pushup(u);
}
void modify(int u,int l,int r,int val){
	if(tr[u].l>=l&&tr[u].r<=r){
		tr[u].sum+=val*(tr[u].r-tr[u].l+1);//需要加很多个val 
		tr[u].lazy+=val;//懒标记一下,标记加上过val
		return; 
	}
	pushdown(u);//懒标记下传
	int mid=(tr[u].l+tr[u].r)>>1;
	if(mid>=l) modify(u<<1,l,r,val);
	if(mid<r) modify(u<<1|1,l,r,val);
	pushup(u); 
}
int ask(int u,int l,int r){
	if(tr[u].l>=l&&tr[u].r<=r){
		return tr[u].sum;
	}
	pushdown(u);
	int mid=(tr[u].l+tr[u].r)>>1,sum=0;
	if(mid>=l) sum+=ask(u<<1,l,r);
	if(mid<r) sum+=ask(u<<1|1,l,r);
	return sum;
}
signed main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	build(1,1,n);
	while(m--){
		cin>>op;
		if(op==1){
			cin>>x>>y>>k;
			modify(1,x,y,k);
		}else{
			cin>>x>>y;
			cout<<ask(1,x,y)<<endl;
		}
	} 
	return 0;
}

树状数组

单点修改区间查询

void add(int x,int k){//将a[x]加上k 
	for(;x<N;x+=x&-x){
		tr[x]+=k;
	}
}
int ask(int x){//求1-x的和 
	int ans=0;
	for(;x;x-=x&-x){
		ans+=tr[x];
	}
	return ans;
}

区间修改单点查询

不使用树状数组维护 \(a_i\),而是维护差分数组 \(cf_i=a_i-a_{i-1}\)

修改:

cin>>x>>y>>k;
add(x,k);
add(y+1,-k);

查询:

cin>>x;
cout<<ask(x)<<endl;

区间修改区间查询

开两个树状数组:int tr[N][2];

修改、查询:

void add(int x,int k,int op){
	for(;x<N;x+=x&-x){
		tr[x][op]+=k;
	}
}
int ask(int x,int op){
	int ans=0;
	for(;x;x-=x&-x){
		ans+=tr[x][op];
	}
	return ans;
}

初始化:

for(int i=1;i<=n;i++){
  cin>>a[i];
  add(i,a[i]-a[i-1],0);
  add(i,i*(a[i]-a[i-1]),1); 
}

查询:

for(int i=1,op,x,y,k;i<=m;i++){
  cin>>op>>x>>y;
  if(op==1){
    cin>>k;
    add(x,k,0);
    add(y+1,-k,0);
    add(x,x*k,1);
    add(y+1,-(y+1)*k,1);
  }else{
    cout<<solve(y)-solve(x-1)<<endl;
  }
}

并查集

【优化】路径压缩

int find(int x){//查
	if(f[x]==x) return x;
	else return f[x]=find(f[x]); 
}
void merge(int x,int y){//并 
	int a=find(x),b=find(y);
	if(a!=b) f[a]=b;
}

【优化】启发式合并

int f[N],siz[N];
int find(int x){
	if(f[x]==x) return x;
	return f[x]=find(f[x]);
}
void merge(int x,int y){
	int a=find(x),b=find(y);
//	if(a!=b) f[a]=b;
	if(a==b) return;
	if(siz[a]>siz[b]){
		f[b]=a;
		siz[a]+=siz[b];
	}else{
		f[a]=b;
		siz[b]+=siz[a];
	}
}
//主函数中for(int i=1;i<=N;i++) siz[i]=1;

【优化】随机合并

//#include<cstdlib>

int find(int x){
	if(f[x]==x) return x;
	return f[x]=find(f[x]);
}
void merge(int x,int y){
	int a=find(x),b=find(y);
	if(a==b) return;
	if(rand()&1) /*rand()%2==0*/f[a]=b;
	else f[b]=a;
}

平衡树

Splay

int getwh(int x){return ch[f[x]][1]==x;}
void pushup(int x){
	sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+cnt[x];
}
void rotate(int x){//转 
	int y=f[x],z=f[y],k=getwh(x);//y是爸爸,z是爷爷 
	f[x]=z;
	ch[z][getwh(y)]=x;
	f[ch[x][k^1]]=y;
	ch[y][k]=ch[x][k^1];
	f[y]=x;
	ch[x][k^1]=y;
	pushup(y);
	pushup(x);
}
void splay(int x,int tar){//把x旋转到tar的儿子 
	if(x==-1) return;
	while(f[x]!=tar){
		int y=f[x],z=f[y];
		if(z!=tar){
			if(getwh(y)==getwh(x)) rotate(y);//共线 
			else rotate(x);
		}
		rotate(x);
	}
	if(tar==0) root=x;
}
void insert(int v){//插入v 
	int x=root,y=0;
	while(x&&v!=a[x]){//看看v要插入到哪里 
		y=x;
		x=ch[x][v>a[x]];
	}
	if(x) cnt[x]++,sum[x]++;//有v这个节点 
	else{//没有 
		x=++tot;
		if(y) ch[y][v>a[y]]=x;//有父亲
		f[x]=y;
		sum[x]=cnt[x]=1;//初始化子树大小、值的个数 
		a[x]=v; 
	}
	splay(x,0);
}
void find(int v){//找到v并旋转到根节点 
	int x=root;
	if(!x) return;//根节点
	while(ch[x][v>a[x]]&&v!=a[x]) x=ch[x][v>a[x]];//有儿子就一直往下找
	splay(x,0);//转到根 
}
int nxt(int v,int f){
	find(v);//旋到根 
	int x=root;
	if(a[x]>v&&f==1) return x;//后继
	if(a[x]<v&&f==0) return x;//前驱
	x=ch[x][f];//走一步 
	while(ch[x][f^1]) x=ch[x][f^1];//一直往下,反方向走 
	return x; 
}
void erase(int v){
	int pre=nxt(v,0),next=nxt(v,1);//找前驱和后继
	splay(pre,0);splay(next,pre);
	int x=ch[next][0];//v一定到了next左边
	if(cnt[x]>1){//v这个值不止一个 
		cnt[x]--;
		pushup(x);
		splay(x,0);
	}else{
		ch[next][0]=0;//删掉后继的左儿子 
		f[x]=0;
	}
}
int getrank(int v){//v的排名,有多少个数小于v 
	int x=root,rank=0;
	while(x){
		if(a[x]>v) x=ch[x][0];//大了,往左走
		else if(a[x]==v){//找到了
			rank+=sum[ch[x][0]]; 
			tag=x;
			return rank;
		} 
		else{
			rank+=sum[ch[x][0]]+cnt[x];
			x=ch[x][1];//小了,往右走 
		}
	}
	return rank;
}
int kth(int k){
	int x=root;
	while(1){
		if(sum[ch[x][0]]>=k) x=ch[x][0];//左边有至少k个,一定在左边
		else if(sum[ch[x][0]]+cnt[x]>=k){//左边不够,加上自己够了,一定是自己
			tag=x;
			return a[x];
		} 
		else{//在右边,往右走 
			k-=sum[ch[x][0]]+cnt[x];
			x=ch[x][1]; 
		} 
	}
}

FHQ-Treap

mt19937 rd(time(0));
struct node{
	int l,r;
	int val,key;//key随机分配 
	int sum;
}tr[N];
void pushup(int u){
	tr[u].sum=tr[ls].sum+tr[rs].sum+1;
}
void split(int u,int val,int &x,int &y){//分裂 
	if(!u){
		x=y=0;//到了底部
		return;
	}
	if(tr[u].val<=val){//值小了 
		x=u;
		split(rs,val,rs,y);//往右分裂 
	}else{//值大了 
		y=u;
		split(ls,val,x,ls);//往左分裂 
	}
	pushup(u);
}
int merge(int x,int y){//合并 
	if(!x||!y) return x+y;//一上一下,直接合并 
	if(tr[x].key>tr[y].key){//x大,y当x儿子 
		tr[x].r=merge(tr[x].r,y);
		pushup(x);
		return x;
	}else{//y大,x当y儿子 
		tr[y].l=merge(x,tr[y].l);
		pushup(y);
		return y;
	}
}
int new_node(int val){
	tr[++cnt]=(node){NULL,NULL,val,rd(),1};//无左右儿子,key随机生成 
	return cnt;
}
void insert(int val){
	split(root,val,x,y);//从val开始分裂
	root=merge(merge(x,new_node(val)),y);//合并两次 
}
void erase(int val){
	split(root,val,x,z);//x<=val  z>val
	split(x,val-1,x,y);//x<val  y==val
	y=merge(tr[y].l,tr[y].r);
	root=merge(merge(x,y),z);
}
int getrank(int val){
	x=root;
	int rank=0;
	while(x){
		if(tr[x].val<val) rank+=tr[tr[x].l].sum+1,x=tr[x].r;//往右 
		else x=tr[x].l;//往左 
	}
	return rank;
}
int kth(int k){
	x=root;
	while(x){
		if(tr[tr[x].l].sum>=k) x=tr[x].l;//左子树够了,往左跳
		else if(tr[tr[x].l].sum+1>=k) return tr[x].val;//正好是自己
		else{//左边不够 
			k-=tr[tr[x].l].sum+1;
			x=tr[x].r;//往右跳 
		} 
	}
}
int pre(int val){
	split(root,val-1,x,y);//往左跳一下 
	int u=x;
	while(tr[u].r) u=tr[u].r;//一直往右跳 
	merge(x,y);
	return tr[u].val;
}
int nxt(int val){
	split(root,val,x,y);//往左跳一下 
	int u=y;
	while(tr[u].l) u=tr[u].l;//一直往右跳 
	merge(x,y);
	return tr[u].val;
}

文艺平衡树

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define l(x) (tr[x].l)
#define r(x) (tr[x].r)
#define f(x) (tr[x].f)
#define val(x) (tr[x].val)
#define sum(x) (tr[x].sum)
#define cnt(x) (tr[x].cnt)
#define lazy(x) (tr[x].lazy)
using namespace std;
int n,m;
const int N=100005;
struct node{
	int l,r,f;
	int val;
	int sum;
	int lazy;//懒标记 
}tr[N];
int root,cnt=0;
void pushup(int u){
	sum(u)=sum(l(u))+sum(r(u))+1;
}
void pushdown(int u){//旋转子树 
	if(lazy(u)){
		swap(l(u),r(u));
		lazy(l(u))^=1;
		lazy(r(u))^=1;
		lazy(u)=0;
	}
}
int getwh(int x){
	return r(f(x))==x;
}
void rotate(int x){
	int y=f(x),z=f(y),k=getwh(x);
	f(x)=z;
	if(getwh(y)) r(z)=x;
	else l(z)=x;
	if(k){
		f(l(x))=y;
		r(y)=l(x);
		f(y)=x;
		l(x)=y;
	}else{
		f(r(x))=y;
		l(y)=r(x);
		f(y)=x;
		r(x)=y;
	}
	pushup(y);
	pushup(x);
}
void splay(int x,int tar){
	while(f(x)!=tar){
		int y=f(x),z=f(y);
		if(z!=tar){
			if(getwh(y)==getwh(x)) rotate(y);
			else rotate(x);
		}
		rotate(x);
	}
	if(!tar) root=x;
}
int build(int l,int r,int f){//建树 
	if(l>r) return 0;
	int mid=(l+r)>>1,val=mid-1,tmp=++cnt;
	if(val==0) val=-2e9;
	else if(val==n+1) val=2e9;
	//建左右 
	tr[tmp]=(node){build(l,mid-1,tmp),build(mid+1,r,tmp),f,val,0,0};
	pushup(tmp);
	return tmp;
}
int kth(int k){//第几大,和之前没有区别 
	int x=root;
	while(x){
		pushdown(x);
		if(sum(l(x))>=k) x=l(x);
		else if(sum(l(x))+1>=k) return x;
		else{
			k-=sum(l(x))+1;
			x=r(x);
		}
	}
}
void print(int x){
	pushdown(x);
	if(l(x)) print(l(x));
	if(abs(val(x))!=2e9) cout<<val(x)<<' ';
	if(r(x)) print(r(x));
}
signed main(int argc,char *argv[]){
	ios::sync_with_stdio(NULL);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	root=build(1,n+2,0);
	for(int i=1,l,r,pre,nxt;i<=m;i++){
		cin>>l>>r;
		l++,r++;
		pre=kth(l-1),nxt=kth(r+1);
		splay(pre,0);
		splay(nxt,pre);
		lazy(l(r(root)))^=1;
	}
	print(root);
	return 0;
}

二分

二分答案万能模板

bool check(int x){
	//TODO
}
int find(){
	int l=1,r=1e9,opt=-1;
	while(l<=r){
		int mid=(l+r)>>1;
		if(opt==mid) break;
		opt=mid;
		if(check(mid)) r=mid;
		else l=mid;
	}
	if(check(min(l,r))) return min(l,r);
	else return max(l,r);
}

二分,但是实数

const double eps=1e-6;//eps,误差值
while(r-l>eps){
	double mid=(l+r)/2;
	if(check(mid)) r=mid;
	else l=mid; 
} 

离散化

创建离散化 vector

vector<int> num;

\(a_i\) 离散化后的值

int get(int x){
	return lower_bound(num.begin(),num.end(),x)-num.begin();
}

离散化

sort(num.begin(),num.end());
num.erase(unique(num.begin(),num.end()),num.end());

数学 & 数论

中缀表达式转表达式树

long long dfs(int l,int r){
	int x=0,y=0,z=0;
	for(int i=l;i<=r;i++){
		if(a[i]=='(') x++;
		else if(a[i]==')') x--;
		else{
			if(x==0&&(a[i]<'0'||a[i]>'9')){
				if(a[i]=='*'||a[i]=='/') y=i;
				else z=i;
			}
		}
	}
	if(z){
		tree[z].l=dfs(l,z-1);
		tree[z].r=dfs(z+1,r);
		return z;
	}
	if(y){
		tree[y].l=dfs(l,y-1);
		tree[y].r=dfs(y+1,r);
		return y;
	}
	if(a[l]=='('&&a[r]==')') return dfs(l+1,r-1); 
	int k=0;
	for(int i=l;i<=r;i++){
		k=k*10+a[i]-'0';
	}
	tree[l].val=k;
	return l;
}

void pre(int x){//遍历
	if(tree[x].l) pre(tree[x].l);
	if(tree[x].r) pre(tree[x].r);
	c[++cnt]=x;
}

gcd

int gcd(int x,int y){
	if(y==0) return x;
	else return gcd(y,x%y);
}

exgcd

ll exgcd(ll a,ll b,ll &x,ll &y){
	if(b==0){
		x=1,y=0;
		return a;
	}
	ll d=exgcd(b,a%b,y,x);
	y-=a/b*x;
	return d;
}

快速幂

正常版

ll qpow(ll a,ll b,ll m){
	ll ans=1;
	while(b){
		if(b&1) ans=ans*a%m;//b%2==1
		a=a*a%m;
		b>>=1;//b/=2
	} 
	return ans;
}

压行版

ll Pow(ll a,ll b,ll mod){
	ll ans=1;
	for(;b;a=a*a%mod,b>>=1){
		if(b&1) ans=ans*a%mod;
	}
	return ans;
}

素数筛法

埃氏筛法

void get_all_prime() {
	int cnt=0;
	prime[0]=1;
	prime[1]=1;
	for(int i=2; i<=40000; i++) {
		if(!prime[i]) {
			for(int j=2*i; j<=40000; j+=i) {
				prime[j]=0;
			}
		}
	}
}

欧拉筛 & 线性筛

for(int i=2;i<=n;i++){
  if(!vis[i]) p.push_back(i);//如果是质数,就把它放进质数数组里 
  for(int j=0;j<p.size();j++){//遍历所有质数 
    if(i*p[j]>n) break;//边界情况 
    vis[i*p[j]]=1;//标记合数 
    if(i%p[j]==0) break;//能整除就退出,线性筛特点 
  }
}

素数判定

正常判

bool prime(int x){
	if(x==0||x==1) return 0;
	if(x==2) return 1;
	for(int i=2;i*i<=x;i++){
		if(x%i==0) return 0;
	}
	return 1;
}

Miller-Rabin

int p[12]={2,3,5,7,11,13,17,19,23,29,31,37};
ll Pow(ll a,ll b,ll p){//快速幂
	ll ans=1;
	while(b){
		if(b&1) ans=ans*a%p;
		a=a*a%p;
		b>>=1;
	}
	return ans;
}
ll Mul(ll a,ll b,ll p){//龟速乘
	a%=p,b%=p;
	ll k=(long double)a*b/p;
	long double ans=a*b-k*p;
	return (ll)(ans+p)%p;
}
bool miller_rabin(ll x){
	if(x==0||x==1) return 0;
	if(x==2) return 1;
	if(x%2==0) return 0;
	ll s=x-1,t=0;
	while(s%2==0) t++,s>>=1;
	for(int i=0;i<12&&p[i]<x;i++){
		if(x%p[i]==0) return 0;
		ll pre=Pow(p[i],s,x),tmp=pre;
		for(int j=1;j<=t;j++){
			tmp=Mul(tmp,tmp,x);
			if(tmp==1&&pre!=1&&pre!=x-1) return 0;
			pre=tmp;
		}
		if(tmp!=1) return 0;
	}
	return 1;
}

逆元

给定 \(n,p\)\(1\sim n\) 中所有整数在模 \(p\) 意义下的乘法逆元。

\(a\)\(p\) 的乘法逆元定义为 \(ax\equiv1\pmod p\) 的解。

费马小定理

条件:\(p\) 为质数。

Pow(n,p-2,p);//快速幂

扩展欧几里得

条件:无。【万能钥匙】

exgcd(n,p,x,y);//扩展欧几里得模板
//答案:(x%p+p)%p

递推求逆元

inv[1]=1;
for(ll i=2;i<=n;i++){
    inv[i]=(p-p/i)*inv[p%i]%p;
}

卢卡斯定理

int Lucas(int n,int m){
	if(m==0) return 1;
	else return (Lucas(n/p,m/p)%p*C(n%p,m%p)%p)%p;
}

多项式

DFT

const double PI=acos(-1);
const int N=100005;
struct num{//复数类
	double x,y;//x+yi
	num(double xx=0,double yy=0){x=xx,y=yy;}
	num operator +(num const &B) const{return num(x+B.x,y+B.y);}
	num operator -(num const &B) const{return num(x-B.x,y-B.y);}
	num operator *(num const &B) const{return num(x*B.x-y*B.y,x*B.y+y*B.x);}
	//除法没用
}f[N<<1],tmp[N<<1];
void dft(num *f,int len){
	if(len==1) return;//边界条件
	num *f0=f,*f1=f+len/2;
	for(int i=0;i<len;i++) tmp[i]=f[i];//缓存
	for(int i=0;i<(len>>1);i++){//分奇偶打乱
		f0[i]=tmp[i<<1];
		f1[i]=tmp[i<<1|1];
	}
	//分治
	dft(f0,len>>1);
	dft(f1,len>>1);
	num t(cos(2*PI/len),sin(2*PI/len)),buf(1,0);
	for(int i=0;i<(len>>1);i++){
		tmp[i]=f0[i]+buf*f1[i];
		tmp[i+(len>>1)]=f0[i]-buf*f1[i];
		buf=buf*t;//旋转
	}
	for(int i=0;i<len;i++) f[i]=tmp[i];//放回
}

FFT

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
int n,m;
const double PI=acos(-1);
const int N=2000005;
struct num{
	double x,y;//x+yi
	num(double xx=0,double yy=0){x=xx,y=yy;}
	num operator +(num const &B) const{return num(x+B.x,y+B.y);}
	num operator -(num const &B) const{return num(x-B.x,y-B.y);}
	num operator *(num const &B) const{return num(x*B.x-y*B.y,x*B.y+y*B.x);}
	//除法没用
}f[N<<1],g[N<<1],tmp[N<<1];
void fft(num *f,int len,int type){
	if(len==1) return;//边界条件
	num *f0=f,*f1=f+(len>>1);
	for(int i=0;i<len;i++) tmp[i]=f[i];//缓存
	for(int i=0;i<(len>>1);i++){//分奇偶打乱
		f0[i]=tmp[i<<1];
		f1[i]=tmp[i<<1|1];
	}
	//分治
	fft(f0,len>>1,type);
	fft(f1,len>>1,type);
	num t(cos(2*PI/len),type*sin(2*PI/len)),buf(1,0);
	for(int i=0;i<(len>>1);i++){
		tmp[i]=f0[i]+buf*f1[i];
		tmp[i+(len>>1)]=f0[i]-buf*f1[i];
		buf=buf*t;//旋转
	}
	for(int i=0;i<len;i++) f[i]=tmp[i];//放回
}
int ans[N];
signed main(int argc,char *argv[]){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ios::sync_with_stdio(NULL);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=0;i<=n;i++) cin>>f[i].x;
	for(int i=0;i<=m;i++) cin>>g[i].x;
	int lim=1;
	for(;lim<=n+m;lim<<=1);
	fft(f,lim,1);fft(g,lim,1);
	for(int i=0;i<=lim;i++){
		f[i]=f[i]*g[i];
	}
	fft(f,lim,-1);
	for(int i=0;i<=lim;i++) ans[i]+=int(f[i].x/lim+0.5);
	for(int i=0;i<=n+m;i++) cout<<ans[i]<<' ';
	cout<<endl;
	return 0;
}

FFT 非递归

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
int n,m;
const double PI=acos(-1);
const int N=2000005;
int r[N<<1];
struct num{
	double x,y;//x+yi
	num(double xx=0,double yy=0){x=xx,y=yy;}
	num operator +(num const &B) const{return num(x+B.x,y+B.y);}
	num operator -(num const &B) const{return num(x-B.x,y-B.y);}
	num operator *(num const &B) const{return num(x*B.x-y*B.y,x*B.y+y*B.x);}
	//除法没用
}a[N<<1];
void fft(num *f,int lim,int type){
	for(int i=0;i<lim;i++){//重新排列元素
		if(i<r[i]) swap(f[i],f[r[i]]);
	}
	for(int mid=1;mid<lim;mid<<=1){//当前区间长度
		num t(cos(PI/mid),type*sin(PI/mid));//单位根初始化
		for(int len=mid<<1,j=0;j<lim;j+=len){
			num w(1,0);//平躺单位根
			for(int i=0;i<mid;i++,w=w*t){//旋转
				num x=f[i+j],y=w*f[i+j+mid];
				f[i+j]=x+y;
				f[i+j+mid]=x-y;
			}
		}
	}
	if(type==-1){
		for(int i=0;i<lim;i++){
			a[i].x/=lim;
			a[i].y/=lim;
		}
	}
}
int ans[N];
int L;
signed main(int argc,char *argv[]){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ios::sync_with_stdio(NULL);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=0;i<=n;i++) cin>>a[i].x;
	for(int i=0;i<=m;i++) cin>>a[i].y;
	int lim=1;
	for(;lim<=n+m;lim<<=1,L++);
	for(int i=0;i<=lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
	fft(a,lim,1);
	for(int i=0;i<=lim;i++) a[i]=a[i]*a[i];
	fft(a,lim,-1);
	for(int i=0;i<=n+m;i++){
		cout<<int(a[i].y/2+0.5)<<' ';
	}
	return 0;
}

FFT 三步变两步

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
int n,m;
const double PI=acos(-1);
const int N=2000005;
int r[N<<1];
struct num{
	double x,y;//x+yi
	num(double xx=0,double yy=0){x=xx,y=yy;}
	num operator +(num const &B) const{return num(x+B.x,y+B.y);}
	num operator -(num const &B) const{return num(x-B.x,y-B.y);}
	num operator *(num const &B) const{return num(x*B.x-y*B.y,x*B.y+y*B.x);}
	//除法没用
}a[N<<1];
void fft(num *f,int lim,int type){
	for(int i=0;i<lim;i++){//重新排列元素
		if(i<r[i]) swap(f[i],f[r[i]]);
	}
	for(int mid=1;mid<lim;mid<<=1){//当前区间长度
		num t(cos(PI/mid),type*sin(PI/mid));//单位根初始化
		for(int len=mid<<1,j=0;j<lim;j+=len){
			num w(1,0);//平躺单位根
			for(int i=0;i<mid;i++,w=w*t){//旋转
				num x=f[i+j],y=w*f[i+j+mid];
				f[i+j]=x+y;
				f[i+j+mid]=x-y;
			}
		}
	}
	if(type==-1){
		for(int i=0;i<lim;i++){
			a[i].x/=lim;
			a[i].y/=lim;
		}
	}
}
int ans[N];
int L;
signed main(int argc,char *argv[]){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ios::sync_with_stdio(NULL);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=0;i<=n;i++) cin>>a[i].x;
	for(int i=0;i<=m;i++) cin>>a[i].y;
	int lim=1;
	for(;lim<=n+m;lim<<=1,L++);
	for(int i=0;i<=lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
	fft(a,lim,1);
	for(int i=0;i<=lim;i++) a[i]=a[i]*a[i];
	fft(a,lim,-1);
	for(int i=0;i<=n+m;i++){
		cout<<int(a[i].y/2+0.5)<<' ';
	}
	return 0;
}

NTT

void dtt(ll *f,int lim,int type){
	for(int i=0;i<lim;i++){
		if(i<r[i]) swap(f[i],f[r[i]]);
	}
	for(int mid=1;mid<lim;mid<<=1){
		//g原根,gi原根逆元
		ll t=Pow(type==1?g:gi,(mod-1)/(mid<<1));
		for(int j=0;j<lim;j+=(mid<<1)){
			ll w=1;
			for(int i=0;i<mid;i++,w=(w*t)%mod){
				int x=f[i+j],y=w*f[i+j+mid]%mod;
				f[i+j]=(x+y)%mod;
				f[i+j+mid]=(x-y+mod)%mod;
			}
		}
	}
}

BSGS

//求最小的x,使得a^x%p==b%p,也就是求离散对数log_a b
ll BSGS(ll a,ll b,ll p){
	a%=p,b%=p;
	if(b==1) return 0;//x=0
	unordered_map<int,int> mp;
	ll m=ceil(sqrt(p)),t=b;
	mp[t]=0;
	for(int i=1;i<m;i++){
		t=t*a%p;
		mp[t]=i;
	}
	ll s=Pow(a,m,p);
	t=1;
	for(int i=1;i<=m;i++){
		t=t*s%p;
		if(mp.count(t)>0) return i*m-mp[t];
	}
	return -1;
}

矩阵

const int N=3;
struct mtx{
	int n,m;
	ll a[N+5][N+5];
	mtx(){memset(a,0,sizeof(a));}
	friend mtx operator *(mtx a,mtx b){//a.m==b.n
		mtx ans;
		ans.n=a.n;ans.m=b.m;
		up(i,1,a.n){
			up(j,1,b.m){
				up(k,1,a.m){
					ans.a[i][j]+=(ll)a.a[i][k]*b.a[k][j];
					ans.a[i][j]%=mod;
				}
			}
		}
		return ans;
	}
};
mtx Pow(mtx a,int k){//a.n==a.m
	mtx ans;
	ans.n=ans.m=a.n;
	up(i,1,ans.n) ans.a[i][i]=1;
	while(k){
		if(k&1) ans=ans*a;
		a=a*a;
		k>>=1;
	}
	return ans;
}

加快程序运行速度程序

快读&写

快读

inline int read() {
	int x=0,f=1;
	char c=getchar();//读入第一个字符
	while(c<'0'||c>'9') {//如果这个字符不是数字
		if(c=='-')f=-1;//那么只能是减号,也就是负数标记
		c=getchar();//继续读入
	}
	while(c>='0'&&c<='9') {
		x=(x<<3)+(x<<1)+c-48;//将字符转换为数字
		c=getchar();//继续读入
	}
	return x*f;//返回这个数字
}

快写

void write(int x) {
	if (x < 0) {
		putchar('-');//如果这个数小于0,说明它是负数,先输出负数标记
		x = -x;//将这个数变成负数的它
	}
	if (x > 9) {
		write(x / 10);//递归式
	}
	putchar(x % 10 + '0');//输出数字
	return ;
}

tie(0)

ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);

超级快读

https://www.luogu.me/paste/ilt13pl4

namespace Fast_I{
	char *_Buf,*_Start_ptr,*_End_ptr;
	streambuf *inbuf;
	unsigned int Size;
	bool _Ok;
	struct Fast_Istream{
		operator bool(){return _Ok;}
		Fast_Istream(streambuf *in,unsigned int Sz){
			_Ok=1;
			Fast_I::Size=Sz;
			inbuf=in;
			_Start_ptr=_End_ptr=_Buf=new char[Sz];
		}
		Fast_Istream(const char *in,unsigned int Sz){
			_Ok=1;
			Fast_I::Size=Sz;
			rdbuf(in);
			_Start_ptr=_End_ptr=_Buf=new char[Sz];
		}
		Fast_Istream(unsigned int Sz){
			_Ok=1;
			Fast_I::Size=Sz;
			_Start_ptr=_End_ptr=_Buf=new char[Sz];
		}
		void rdbuf(const char *File){
			static ifstream __In__(File);
			rdbuf(__In__.rdbuf());
		}
		void Get_Char(char &_Val){
			if(_Start_ptr==_End_ptr){
				_Start_ptr=_Buf;
				_End_ptr=_Buf+inbuf->sgetn(_Buf,Size);
			}
			if(_Start_ptr==_End_ptr){
				_Val=-1;
				_Ok=0;
			}else _Val=*_Start_ptr++;
		}
		Fast_Istream &operator>>(char &_Val){
			if(_Ok){
				Get_Char(_Val);
				while(_Val==32||_Val==10||_Val==13||_Val==8||_Val==9||_Val==7||_Val==12||_Val==11) Get_Char(_Val);
			}
			return *this;
		}
		Fast_Istream &operator>>(char *_Val){
			if(_Ok){
				Get_Char(*_Val);
				while(*_Val==32||*_Val==10||*_Val==13||*_Val==8||*_Val==9||*_Val==7||*_Val==12||*_Val==11) Get_Char(*_Val);
				while(*_Val!=32&&*_Val!=10&&*_Val&&*_Val!=-1&&*_Val!=9 &&*_Val!=11&&*_Val!=12&&~*_Val) Get_Char(*++_Val);
				*_Val=0;
				--_Start_ptr;
			}
			return *this;
		}
		Fast_Istream &operator>>(string &_Val){
			if(_Ok){
				char c;
				Get_Char(c);
				while(c==32||c==10||c==13||c==8||c==9||c==7||c==12||c==11) Get_Char(c);
				for(_Val.clear();c!=32&&c!=10&&c&&c!=-1&&c!=9&&c!=11&&c!=12&&~c;Get_Char(c)) _Val.push_back(c);
				--_Start_ptr;
			}
			return *this;
		}
		template <typename Typex>
		void Get_Int(Typex &_Val){
			if(_Ok){
				char ch;
				bool _F=0;
				for(Get_Char(ch);(ch<48||ch>57)&&~ch;Get_Char(ch)) _F=ch==45;
				for(_Val=0;ch>47&&ch<58&&~ch;Get_Char(ch)) _Val=_Val*10+(ch^48);
				if(_F) _Val=~_Val+1;
				--_Start_ptr;
			}
		}
		template <typename Typex>
		void Get_Unsigned(Typex &_Val){
			if(_Ok){
				char ch;
				Get_Char(ch);
				while((ch<48||ch>57)&&~ch) Get_Char(ch);
				for(_Val=0;ch>47&&ch<58&&~ch;Get_Char(ch)) _Val=_Val*10+(ch^48);
				--_Start_ptr;
			}
		}
		template <typename Typex>
		void Get_Double(Typex &_Val){
			if(_Ok){
				char ch;
				bool _F=0;
				for(Get_Char(ch);(ch<48||ch>57)&&~ch;Get_Char(ch)) _F=ch==45;
				for(_Val=0;ch>47&&ch<58&&~ch;Get_Char(ch)) _Val=_Val*10+(ch^48);
				if(ch==46){
					unsigned long long _Pow=1;
					for(Get_Char(ch);ch>47&&ch<58&&~ch;Get_Char(ch)) _Val+=Typex((ch^48)*1.0/(_Pow*=10));
				}
				if(_F) _Val=-_Val;
				--_Start_ptr;
			}
		}
		Fast_Istream &operator>>(bool &_Val){
			if(_Ok){
				char ch;
				Get_Char(ch);
				while(ch==32||ch==10||ch==13||ch==8||ch==9||ch==7||ch==12||ch==11) Get_Char(ch);
				while(ch!=32&&ch!=10&&ch&&~ch&&ch!=9&&ch!=11&&ch!=12&&~ch){
					_Val|=ch!=48;
					Get_Char(ch);
				}
				--_Start_ptr;
			}
			return *this;
		}
		Fast_Istream &operator>>(short &_Val){
			Get_Int(_Val);
			return *this;
		}
		Fast_Istream &operator>>(int &_Val){
			Get_Int(_Val);
			return *this;
		}
		Fast_Istream &operator>>(long &_Val){
			Get_Int(_Val);
			return *this;
		}
		Fast_Istream &operator>>(long long &_Val){
			Get_Int(_Val);
			return *this;
		}
		Fast_Istream &operator>>(unsigned short &_Val){
			Get_Unsigned(_Val);
			return *this;
		}
		Fast_Istream &operator>>(unsigned int &_Val){
			Get_Unsigned(_Val);
			return *this;
		}
		Fast_Istream &operator>>(unsigned long &_Val){
			Get_Unsigned(_Val);
			return *this;
		}
		Fast_Istream &operator>>(unsigned long long &_Val){
			Get_Unsigned(_Val);
			return *this;
		}
		Fast_Istream &operator>>(float &_Val){
			Get_Double(_Val);
			return *this;
		}
		Fast_Istream &operator>>(double &_Val){
			Get_Double(_Val);
			return *this;
		}
		Fast_Istream &operator>>(long double &_Val){
			Get_Double(_Val);
			return *this;
		}
		template <typename Typex,typename... More>
		void operator()(Typex &_Val,More &... _More){
			*this>>_Val;
			operator()(_More...);
		}
		void pop(){
			char ch;
			Get_Char(ch);
		}
		char peek(){
			if(_Start_ptr==_End_ptr){
				_Start_ptr=_Buf;
				_End_ptr=_Buf+inbuf->sgetn(_Buf,Size);
			}
			if(_Start_ptr==_End_ptr){
				_Ok=0;
				return -1;
			}else return *_Start_ptr;
		}
		template <typename Typex>
		void operator()(Typex &_Val){*this>>_Val;}
		template <typename Typex,typename...More>
		streambuf *rdbuf(){return inbuf;}
		void rdbuf(streambuf *_inbuf){inbuf=_inbuf;}
		Fast_Istream getline(string &s,char _End='\n'){
			if(_Ok){
				char c;
				Get_Char(c);
				while((c==32||c==10||c==13||c==8||c==9||c==7||c==12||c==11||c==-1)&&c!=_End) Get_Char(c);
				for(s.clear();c!=_End&&~c;Get_Char(c)) s.push_back(c);
				--_Start_ptr;
			}
			return *this;
		}
	};
}
//快写
namespace Fast_O{
	string buf;
	streambuf *outbuf;
	int _M_precision=6;
	struct Fast_Ostream{
		Fast_Ostream(streambuf *out,unsigned int Size){
			buf.reserve(Size);
			outbuf=out;
		}
		Fast_Ostream(std::streambuf* out){outbuf=out;}
		Fast_Ostream(const char *File,unsigned int Size){
			buf.reserve(Size);
			rdbuf(File);
		}
		void rdbuf(const char *File){
			static ofstream __Out__(File);
			rdbuf(__Out__.rdbuf());
		}
		Fast_Ostream(unsigned int Size){buf.reserve(Size);}
		void flush(){
			outbuf->sputn(buf.data(),buf.size());
			buf.clear();
		}
		~Fast_Ostream(){flush();}
		void endl(){buf.push_back('\n');}
		Fast_Ostream &operator<<(char _Val){
			buf.push_back(_Val);
			return *this;
		}
		Fast_Ostream &operator<<(const char *_Val){
			while(*_Val) buf.push_back(*_Val++);
			return *this;
		}
		Fast_Ostream &operator<<(const string &_Val){
			buf+=_Val;
			return *this;
		}
		template <typename Typex>
		void Put_Unsigned(Typex _Val){
			char *_Stack=(char *)malloc(sizeof(Typex)*3);
			unsigned S_top=0;
			while(_Val){
				_Stack[++S_top]=(_Val%10)^48;
				_Val/=10;
			}
			if(!S_top) buf.push_back('0');
			while(S_top) buf.push_back(_Stack[S_top--]);
			free(_Stack);
		}
		template <typename Typex>
		void Put_Int(Typex _Val){
			if(_Val<0){
				buf.push_back('-');
				Put_Unsigned(~_Val+1);
			}else Put_Unsigned(_Val);
		}
		Fast_Ostream &operator<<(bool _Val){
			buf.push_back(_Val?'1':'0');
			return *this;
		}
		Fast_Ostream &operator<<(short _Val){
			Put_Int(_Val);
			return *this;
		}
		Fast_Ostream &operator<<(int _Val){
			Put_Int(_Val);
			return *this;
		}
		Fast_Ostream &operator<<(long _Val){
			Put_Int(_Val);
			return *this;
		}
		Fast_Ostream &operator<<(long long _Val){
			Put_Int(_Val);
			return *this;
		}
		Fast_Ostream &operator<<(unsigned short _Val){
			Put_Unsigned(_Val);
			return *this;
		}
		Fast_Ostream &operator<<(unsigned int _Val){
			Put_Unsigned(_Val);
			return *this;
		}
		Fast_Ostream &operator<<(unsigned long _Val){
			Put_Unsigned(_Val);
			return *this;
		}
		Fast_Ostream &operator<<(unsigned long long _Val){
			Put_Unsigned(_Val);
			return *this;
		}
		template <typename Typex>
		void endl(const Typex &_Val){*this<<_Val<<'\n';}
		template <typename Typex,typename... More>
		void endl(const Typex &_Val,const More &... _More){
			*this<<_Val;
			endl(_More...);
		}
		template <typename Typex>
		void operator()(const Typex &_Val){*this<<_Val;}
		template <typename Typex,typename... More>
		void operator()(const Typex &_Val,const More &... _More){
			*this<<_Val;
			operator()(_More...);
		}
		std::streambuf *rdbuf(){return outbuf;}
		void rdbuf(std::streambuf *_outbuf){outbuf=_outbuf;}
	};
}
namespace Fast_IO{
	Fast_I::Fast_Istream fin(cin.rdbuf(),16777216);
	Fast_O::Fast_Ostream fout(cout.rdbuf());
}

高精

太多了写不下,去看这里

排序

桶排序

for(int i=0;i<1000;i++){
  int x;
  cin>>x;
  a[x]++;
}
for(int i=1000;i>=1;i--){
  for(int j=1;j<=a[i];j++){
    cout<<i<<' ';
  }
}

冒泡排序

for(int i=1;i<n;i++){
  for(int j=1;j<=n-i;j++){
    if(a[j]>a[j+1]){
      swap(a[j],a[j+1]);
    }
  }
}

选择排序

for(int i=1;i<=n-1;i++){
  k=i;
  for(int j=i+1;j<=n;j++){
    if(a[k]>a[j]) k=j;
  }
  if(k!=i) swap(a[k],a[i]);
}

归并排序

void merge(int l,int r){
	if(l==r) return;//边界 
	int mid=(l+r)>>1;//取mid将区间一分为二 
	merge(l,mid),merge(mid+1,r);//分而治之 
	int ans[MAXN];//建立一个临时数组当“罐子” 
	int i=l,j=mid+1,k=l;
	for(;i<=mid&&j<=r&&k<=r;k++){
		if(a[i]<=a[j]){//比较大小找出较小数 
			ans[k]=a[i];//把小的数往罐子里倒 
			i++; 
		}else{
			ans[k]=a[j];
			j++;
		}
	}
	for(;i<=mid;i++) ans[k++]=a[i];//没把所有数都倒进去,接着倒 
	for(;j<=r;j++) ans[k++]=a[j];
	for(int i=l;i<=r;i++){
		a[i]=ans[i];//最后倒回去 
	}
}

快排

void Quicksort(int num[], int left, int right){
    if (right <= left) return;
    int i = left;
    int j = right;
    int key = num[left];
    while (1){
        //从左向右找比key大的值*/
        while (num[i] <= key){
            i++;
            if (i == right) break;
        }
        //从右向左找比key小的值
        while (num[j] >= key){
            j--;
            if (j == left) break;
        }
        if (i >= j) break;
        //交换i,j对应的值
        int temp = num[i];
        num[i] = num[j];
        num[j] = temp;
    }
    //中枢值与j对应值交换
    num[left] = num[j];
    num[j] = key;
    Quicksort(num, left, j - 1);
    Quicksort(num, j + 1, right);
}

sort排序

#include<bits/stdc++.h>
using namespace std;
int a[1005];
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++){
		cout<<a[i]<<' ';
	}
	return 0;
} 

前缀和

一维前缀和

//从x加到y
sum[i]=sum[i-1]+a[i];
ans=sum[y]-sum[x-1];

假二维前缀和

//从(x1,y1)加到(x2,y2)
sum[i][j]=sum[i][j-1]+a[i][j];		
for(int i=x1;i<=x2;i++){
  ans+=sum[i][y2]-sum[i][y1-1];
}

二维前缀和

//从(x1,y1)加到(x2,y2)
sum[i][j]=a[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
ans=sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1];

假三维前缀和

//从(x,y,z)加到(x_,y_,z_)
sum[i][j][k]=sum[i][j-1][k]+sum[i][j][k-1]+a[i][j][k]-sum[i][j-1][k-1];
for(int i=x;i<=x_;i++){
  ans+=sum[i][y_][z_]-sum[i][y-1][z_]-sum[i][y_][z-1]+sum[i][y-1][z-1];
}

实用程序

int 矩阵结构体

const int N=55;
struct matrix{
	int n,m;
	int a[N][N];
	int sum[N][N];
	int tmp[N][N];
	int find(matrix where,int x,int y){
		return where.a[x][y];
	}
	void input(){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				cin>>a[i][j];
				sum[i][j]=sum[i-1][j]+sum[i][j-1]+a[i][j]-sum[i-1][j-1];
			}
		}
	}
	void output(){
		for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){cout<<a[i][j]<<' ';}cout<<endl;}
	}
	void turn_left(){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				tmp[i][j]=a[j][4-i];
			}
		}
		memcpy(a,tmp,sizeof(tmp));
	} 
	void turn_right(){
		for(int i=1;i<=3;i++) turn_left();
	}
	void flip_top(){
		for(int i=1;i<=n/2;i++){
			for(int j=1;j<=m;j++){
				swap(a[i][j],a[n+1-i][j]);
			}
		}
	}
	void flip_left(){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m/2;j++){
				swap(a[i][j],a[i][m+1-j]);
			}
		}
	}
	long long getSum(int x,int y,int x_,int y_){
		long long ret;
		ret=sum[x_][y_]-sum[x-1][y_]-sum[x_][y-1]+sum[x-1][y-1];
		return ret;
	}
};

更改剪切板

void Copy(string TempBin){
    HGLOBAL hMemBin=NULL;
    PCHAR LockBin=NULL;
    OpenClipboard(NULL);
    EmptyClipboard();
    hMemBin=GlobalAlloc(GMEM_MOVEABLE,TempBin.size()+1);
    LockBin=(PCHAR)GlobalLock(hMemBin);
    RtlMoveMemory(LockBin,TempBin.c_str(),TempBin.size()+1);
    GlobalUnlock(hMemBin);
    LockBin=NULL;
    SetClipboardData(CF_TEXT,hMemBin);
    CloseClipboard();
}

树论

LCA

暴力跳

void dfs(int x,int from){//求深度
	deep[x]=deep[from]+1;
	f[x]=from;
	for(int i=0;i<tree[x].size();i++){
		int to=tree[x][i];
		if(from==to) continue;
		dfs(to,x);
	}
}
int lca(int x,int y){
	if(deep[x]>deep[y]) swap(x,y);
	while(deep[x]>deep[y]) y=f[y];
	if(x==y) return x;
	while(x!=y) x=f[x],y=f[y];
	return x;
}

倍增

void dfs(int x,int from){//求深度
	deep[x]=deep[from]+1;
	f[x][0]=from;
	for(int i=1;i<20;i++){
		f[x][i]=f[f[x][i-1]][i-1];
	}
	for(int i=0;i<tree[x].size();i++){
		int to=tree[x][i];
		if(from==to) continue;
		dfs(to,x);
	}
}
int lca(int x,int y){
	if(deep[x]>deep[y]) swap(x,y);
	for(int i=19;i>=0;i--){
		if(deep[f[y][i]]>=deep[x]) y=f[y][i];
	}
	if(x==y) return x;
	for(int i=19;i>=0;i--){
		if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
	}
	return f[x][0];
}

pb_ds

头文件:

#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>//用tree
#include<ext/pb_ds/hash_policy.hpp>//用hash
#include<ext/pb_ds/trie_policy.hpp>//用trie
#include<ext/pb_ds/priority_queue.hpp>//用priority_queue
using namespace __gnu_pbds;

hash_table

定义:

cc_hash_table<int,bool> mp;//稍快
gp_hash_table<int,bool> mp;

使用:

mp[a]=b;
mp.find(x);

平衡树

例题

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#include<ext/pb_ds/trie_policy.hpp>
#include<ext/pb_ds/priority_queue.hpp>
#define ll long long
#define endl '\n'
using namespace std;
using namespace __gnu_pbds;
tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update> tr;
int n;
int cnt=0;
#define to(x,i) (((1ll*x)<<20)+i)//加密
#define bk(x) (x>>20)//解密 
signed main(){
	cin>>n;
	for(int i=1,op,x;i<=n;i++){
		cin>>op>>x;
		if(op==1) tr.insert(to(x,++cnt));
		if(op==2) tr.erase(tr.lower_bound(to(x,0)));//不必加上i 
		if(op==3) cout<<tr.order_of_key(to(x,0))+1<<endl;
		if(op==4) cout<<bk(*tr.find_by_order(x-1))<<endl;//答案解密 
		if(op==5) cout<<bk(*(--tr.lower_bound(to(x,0))))<<endl;
		if(op==6) cout<<bk(*(tr.upper_bound(to(x,n))))<<endl;
	}
	return 0;
}

图论

存储图

链式前向星

struct Edge{
	int to,w,nxt;
}e[MAXM];
int head[MAXN],num;
void add(int from,int to,int w){
	e[++num]=(Edge){to,w,head[from]};
	head[from]=num;
}

传递闭包

Floyd

for(int k=1;k<=n;k++){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            G[i][j]=G[i][j]|G[i][k]&G[k][j];
        }
    }
}

Floyd+bitset

for(int j=1;j<=n;j++){
    for(int i=1;i<=n;i++){
        if(G[i][j]) G[i]|=G[j];
    }
}

最短路

BFS dij dij+堆 Bellman-Ford Floyd SPFA
边权为1 边权非负 边权非负 被菊花图卡
时间 \(n+m\) \(n^2\) \(m \log m\) \(nm\) \(n^3\) \(m \le SPFA \le nm\)
n,m范围 \(n<5000\) \(m<1e6,n>1e4\) \(nm<1e9\) \(n<400\) \(m<1e6,n>1e4\)
其他 单源 单源 单源 单源 多源 单源

Bellman-Ford优化

struct Edge{
	int from,to,w;
}e[500005];//注意!!!如果是无向图开2倍 
int n,m,s,u,v,w;
int d[10005];
int main(){
	cin>>n>>m>>s;
	memset(d,0x3f,sizeof(d));
	for(int i=1;i<=m;i++){
		cin>>u>>v>>w;
		e[i]=(Edge){u,v,w};
		if(u==s) d[v]=w;
	}d[s]=0;
	//Bellman-Ford
	for(int i=1;i<=n-1;i++){
		bool check=0;//注意,这里增加了一个布尔变量 
		for(int j=1;j<=m;j++){
//			d[e[j].to]=min(d[e[j].to],e[j].w+d[e[j].from]);
			if(d[e[j].to]>e[j].w+d[e[j].from]){
				check=1;
				d[e[j].to]=e[j].w+d[e[j].from];
			}
		}
		if(check==0) break;
	}
	for(int i=1;i<=n;i++){
		if(d[i]==0x3f3f3f3f) cout<<0x7fffffff<<' ';
		else cout<<d[i]<<' ';
	}

堆优dijkstra+邻接表

struct node{
	int v,w;
	friend bool operator< (node x,node y){
		return x.w>y.w;
	}
};
vector<node> G[100005];
void dij(int s){
	for(int i=1;i<=n;i++) ans[i]=INF;
	ans[s]=0;
	priority_queue<node> q;
	q.push((node){s,0});
	while(!q.empty()){
		int u=q.top().v;q.pop();
		if(vis[u]) continue;vis[u]=1;
		for(int i=0;i<G[u].size();i++){
			int v=G[u][i].v,w=G[u][i].w;
			if(ans[v]>ans[u]+w){
				ans[v]=ans[u]+w;
				q.push((node){v,ans[v]});
			}
		}
	}
}

堆优dijkstra+链式前向星

//链式前向星 
struct Edge{
	int to,w,next;
}e[200005];

struct Node{
	int x,y;
	friend bool operator < (Node a,Node b){
		return a.y>b.y;
	}
};

int head[100005];
int d[100005];
int num,n,m,s,u,v,w;
void addEdge(int from,int to,int w){
	e[++num]=(Edge){to,w,head[from]};
	head[from]=num;
	return; 
}

//Dijkstra
priority_queue<Node> q;
void dij(int s){
	memset(d,0x3f,sizeof(d));
	for(int i=head[s];i;i=e[i].next){
		d[e[i].to]=e[i].w;
	}
	d[s]=0;
	f[s]=1;
	while(!q.empty()){
		int x=q.top().x;q.pop();
		if(f[x]==1) continue;
		f[x]=1;
		for(int i=head[x];i;i=e[i].next){
			if(d[e[i].to]>d[x]+e[i].w){
				d[e[i].to]=d[x]+e[i].w;
				q.push((Node){e[i].to,d[e[i].to]});
			}
		}
	}
} 

Johnson

int n,m;
const int N=3005,M=6005;
int head[N],cnt=0;
struct node{
	int to,w,nxt;
}e[M<<1];
void addEdge(int u,int v,int w){
	e[++cnt]={v,w,head[u]};
	head[u]=cnt;
}
int h[N];
bool vis[N];
bool spfa(){
	memset(h,0x3f,sizeof(h));h[0]=0;
	memset(vis,0,sizeof(vis));
	queue<int> q;
	q.push(0);
	int cnt[N]={0};
	vis[0]=1;
	while(!q.empty()){
		int f=q.front();q.pop();
		vis[f]=0;
		for(int i=head[f];i;i=e[i].nxt){
			int v=e[i].to,w=e[i].w;
			if(h[v]>h[f]+w){
				h[v]=h[f]+w;
				if(!vis[v]){
					vis[v]=1;
					q.push(v);
					cnt[v]++;
					if(cnt[v]>n) return 0;
				}
			}
		}
	}
	return 1;
}
int dis[N];
#define pii pair<int,int>
void dij(int s){
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	priority_queue<pii,vector<pii>,greater<pii> > q;
	dis[s]=0;
	q.push(mkp(dis[s],s));
	while(!q.empty()){
		int u=q.top()._2nd;q.pop();
		if(vis[u]) continue;
		vis[u]=1;
		for(int i=head[u];i;i=e[i].nxt){
			int v=e[i].to,w=e[i].w;
			if(dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				q.push(mkp(dis[v],v));
			}
		}
	}
}
signed main(int argc,char *argv[]){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n>>m;
	up(i,1,m){
		int u,v,w;
		cin>>u>>v>>w;
		addEdge(u,v,w);
	}
	up(i,1,n) addEdge(0,i,0);
	if(!spfa()){
		cout<<-1<<endl;
		return 0;
	}
	up(i,1,n){
		for(int j=head[i];j;j=e[j].nxt){
			e[j].w=e[j].w+h[i]-h[e[j].to];
		}
	}
	up(i,1,n){
		dij(i);
		ll ans=0;
		up(j,1,n){
			if(dis[j]==0x3f3f3f3f) ans+=1000000000ll*j;
			else ans+=1ll*j*(dis[j]-h[i]+h[j]);
		}
		cout<<ans<<endl;
	}
	return 0;
}

tarjan 全家桶

缩点 SCC

void tarjan(int x){
	dfn[x]=low[x]=++d;
	in[x]=1;
	st.push(x);
	for(int i=head[x];i;i=e[i].nxt){
		int to=e[i].to;
		if(!dfn[to]){
			tarjan(to);
			low[x]=min(low[x],low[to]); 
		}else if(in[to]){
			low[x]=min(low[x],dfn[to]);
		}
	}
	if(dfn[x]==low[x]){
		tot++;
		int t=0;
		do{
			t=st.top();st.pop();
			scc[t]=tot;
			in[t]=0;
		}while(x!=t);
	}
}

求割点

void tarjan(int x){
	dfn[x]=low[x]=++d;
	int sum=0;
	for(int i=head[x];i;i=e[i].nxt){
		int to=e[i].to;
		if(!dfn[to]){
			sum++;
			tarjan(to);
			low[x]=min(low[x],low[to]);
			if(cut[x]) continue;
			if(x==rt) cut[x]=(sum>1);
			else cut[x]=(dfn[x]<=low[to]);
		}else low[x]=min(low[x],dfn[to]);
	}
}

二分图

匈牙利算法

bool find(int x){
	for(int i=0;i<G[x].size();i++){
		int to=G[x][i];
		if(vis[to]) continue;//连过了 
		vis[to]=1;
		if(line[to]==-1||find(line[to])){//没连过或可以找别的 
			line[to]=x;//连上 
			return 1;
		}
	}
	return 0;
}
int hungary(){
	memset(line,-1,sizeof(line));
	for(int i=1;i<=n;i++){
		memset(vis,0,sizeof(vis));
		if(find(i)) ans++;//能找到 
	}
	return ans;
}

网络最大流

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define int long long
using namespace std;
const ll inf=LONG_LONG_MAX;
int n,m,s,t; 
int ans=0;
struct Edge{
	int to,w,nxt;
}e[10005];
int num=1,head[205];
void add(int from,int to,int w){
	e[++num]=(Edge){to,w,head[from]};
	head[from]=num;
}
int dis[205],now[205];
bool bfs(){//构造分层图 
	for(int i=1;i<=n;i++) dis[i]=inf;
	queue<int> q;
	q.push(s);
	dis[s]=0;
	now[s]=head[s];
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=head[x];i;i=e[i].nxt){
			int to=e[i].to;
			if(e[i].w&&dis[to]==inf){
				q.push(to);
				now[to]=head[to];
				dis[to]=dis[x]+1;
				if(to==t) return 1;
			}
		}
	}
	return 0;
}
int dfs(int x,int sum){//sum是整条增广路对最大流的贡献 
	if(x==t) return sum;
	int ans=0;
	for(int i=now[x];i&&sum;i=e[i].nxt){
		now[x]=i;//当前弧优化 
		int to=e[i].to;
		if(e[i].w&&(dis[to]==dis[x]+1)){
			int k=dfs(to,min(sum,e[i].w));//当前最小的剩余容量 
			if(k==0) dis[to]=inf;//剪枝,去掉增广完毕的点 
			e[i].w-=k;
			e[i^1].w+=k;
			ans+=k;//经过该点的所有流量和 
			sum-=k;//经过该点的剩余流量 
		} 
	}
	return ans; 
}
signed main(int argc,char *argv[]){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ios::sync_with_stdio(NULL);
	cin.tie(0),cout.tie(0);
	cin>>n>>m>>s>>t;
	for(int i=1,u,v,w;i<=m;i++){
		cin>>u>>v>>w;
		add(u,v,w);
		add(v,u,0);
	}
	while(bfs()) ans+=dfs(s,inf);
	cout<<ans<<endl;
	return 0;
}

最小生成树

Kruskal 克鲁斯卡尔

sort(Edge+1,Edge+m+1);
	for(int i=1;i<=m;i++){
		if(find(Edge[i].from)!=find(Edge[i].to)){
			cnt++;
			ans+=Edge[i].w;
			merge(Edge[i].from,Edge[i].to);
		}
		if(cnt==n-1) break;
	}

prim 普雷姆

void prim(){
	memset(dis,0x3f,sizeof(dis));
	dis[1]=0;
	while(1){
		int u=0;
		for(int i=1;i<=n;i++){
			if(!vis[i]&&dis[i]<dis[u]) u=i;
		}
		if(!u) break;
		tot++;vis[u]=1;ans+=dis[u];
		for(int i=head[u];i;i=e[i].nxt){
			int v=e[i].to;
			int w=e[i].w;
			if(dis[v]>w) dis[v]=w;
		}
	}
}

最小斯坦纳树

int n,m,k;
const int N=105,M=505,K=2005;
struct Edge{
	int v,w,nxt;
}e[M<<1];
int head[N],cnt=0;
void addEdge(int u,int v,int w){
	e[++cnt]=(Edge){v,w,head[u]};
	head[u]=cnt;
}
int key[N],dp[N][K];
priority_queue<pi,vector<pi>,greater<pi> > q;
bool vis[N];
void dij(int s){
	memset(vis,0,sizeof(vis));
	while(!q.empty()){
		auto f=q.top();q.pop();
		int u=f._2;
		if(vis[u]) continue;
		vis[u]=1;
		for(auto i=head[u];i;i=e[i].nxt){
			int to=e[i].v;
			if(dp[to][s]>dp[u][s]+e[i].w){
				dp[to][s]=dp[u][s]+e[i].w;
				q.push(mkp(dp[to][s],to));
			}
		}
	}
}
signed main(int argc,char *argv[]){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n>>m>>k;
	up(i,1,m){
		int u,v,w;
		cin>>u>>v>>w;
		addEdge(u,v,w);
		addEdge(v,u,w);
	}
	memset(dp,0x3f,sizeof(dp));
	up(i,1,k){
		cin>>key[i];
		dp[key[i]][1<<(i-1)]=0;
	}
	up(s,1,(1<<k)-1){
		up(i,1,n){
			for(int t=s;t;t=(t-1)&s){
				dp[i][s]=min(dp[i][s],dp[i][t]+dp[i][s^t]);
			}
			if(dp[i][s]!=0x3f3f3f3f) q.push(mkp(dp[i][s],i));
		}
		dij(s);
	}
	cout<<dp[key[1]][(1<<k)-1]<<endl;
	return 0;
}

严格次小生成树

const int N=1e5+5;
const int M=3*1e5+5;
int n,m;
int fa[N];//并查集 
bool vis[M];//这个边是否在最小生成树中 
struct Edge{
	int u,v,w;
	friend bool operator< (Edge a,Edge b){
		return a.w<b.w;
	}
}G[M<<1];
vector<Edge> mst[N];
int e;
int find(int x){
	if(fa[x]==x) return x;
	else return fa[x]=find(fa[x]);
}
void merge(int x,int y){
	int a=find(x),b=find(y);
	if(a!=b) fa[a]=b;
}
int sum=0;//最小生成树边权和 
void kruskal(){
	sort(G+1,G+m+1);
	up(i,1,n) fa[i]=i;//初始化并查集
	int cnt=0;
	up(i,1,m){
		int u=G[i].u,v=G[i].v,w=G[i].w;
		if(find(u)!=find(v)){
			merge(u,v);
			vis[i]=1;
			cnt++;
			sum+=w;
			mst[u].push_back((Edge){u,v,w});
			mst[v].push_back((Edge){v,u,w});
		}
		if(cnt==n-1) return;
	} 
}
int d[N],f[N][30],m1[N][30],m2[N][30];
void dfs(int x,int from,int w){
	//if(len>5) return;
	//cout<<x<<endl;
	d[x]=d[from]+1;
	f[x][0]=from;
	m1[x][0]=w;
	m2[x][0]=-inf;
	up(i,1,20){
		f[x][i]=f[f[x][i-1]][i-1];
		m1[x][i]=max(m1[x][i-1],m1[f[x][i-1]][i-1]);
		m2[x][i]=max(m2[x][i-1],m2[f[x][i-1]][i-1]);
		if(m1[x][i-1]>m1[f[x][i-1]][i-1]) m2[x][i]=max(m2[x][i],m1[f[x][i-1]][i-1]);
		else if(m1[x][i-1]<m1[f[x][i-1]][i-1]) m2[x][i]=max(m2[x][i],m1[x][i-1]);
	}
	for(auto to:mst[x]){
		if(to.v==from) continue;
		dfs(to.v,x,to.w);
	}
}
int LCA(int x,int y){
	if(d[x]<d[y]) swap(x,y);//d[x]>d[y]
	dn(i,20,0){
		if(d[f[x][i]]>=d[y]) x=f[x][i];
	}
	if(x==y) return x;
	dn(i,20,0){
		if(f[x][i]!=f[y][i]){
			x=f[x][i];
			y=f[y][i];
		}
	}
	return f[x][0];
}
int work(int x,int y,int maxn){
	int ans=-inf;
	dn(i,20,0){
		if(d[f[x][i]]>=d[y]){
			if(maxn!=m1[x][i]) ans=max(ans,m1[x][i]);
			else ans=max(ans,m2[x][i]);
			x=f[x][i];
		}
	}
	return ans;
}
signed main(int argc,char *argv[]){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n>>m;
	up(i,1,m){
		int u,v,w;
		cin>>u>>v>>w;
		G[i]={u,v,w};
	}
	kruskal();
	dfs(1,0,0);
	int ans=inf;
	up(i,1,m){
		if(vis[i]) continue;
		int u=G[i].u,v=G[i].v,w=G[i].w;
		int lca=LCA(u,v);
		int mu=work(u,lca,w),mv=work(v,lca,w);
		ans=min(ans,sum-max(mu,mv)+w);
	}
	cout<<ans<<endl;
	return 0;
}

dp

01背包

for(int i=1;i<=m;i++){
	for(int j=t;j>=w[i];j--){
		dp[j]=max(dp[j],dp[j-w[i]]+c[i]);
	}
}

01背包算方案数

dp[0]=1;//dp[j]为凑到重量为j的方案数
for(int i=1;i<=n;i++){
	for(int j=m,j>=a[i];j--){
		dp[j]+=dp[j-a[i]];
	}
} 

完全背包

for(int i=1;i<=m;i++){
	for(int j=w[i];j<=t;j++){
		dp[j]=max(dp[j],dp[j-w[i]]+c[i]);
	}
}

多重背包+二进制优化

cin>>n>>m;
for(int i=1;i<=n;i++){
  cin>>a>>b>>s;
  for(int j=1;j<=s;j*=2){
    num++;
    //放入体积、价值 
    w[num]=a*j;
    c[num]=b*j;
    s-=j;//一直往下扣2^n 
  }
  if(s!=0){
    //没放完,把最后的常数放进去 
    num++;
    w[num]=a*s;
    c[num]=b*s;
  }
}
//01
for(int i=1;i<=num;i++){
  for(int j=m;j>=w[i];j--){
    dp[j]=max(dp[j],dp[j-w[i]]+c[i]);//经典01背包模板 
  }
}

数位 dp 模板

const int N=105;
int a[N];
ll f[N][N];
//如果有前导零还要加一个lead参数
ll dfs(int pos,int sta,bool lim){
	if(!pos) return 0;//到了最后一位,根据题意决定返回值 
	if(!lim&&f[pos][sta]==-1) return f[pos][sta];
	ll ans=0,top=lim?a[pos]:9;//如果受限只能搜到a[pos] 
	for(int i=0;i<=top;i++){
		int newsta;
		if(1) newsta=sta+1;//满足条件,更新状态
		//状态转移 
		ans+=dfs(pos-1,newsta,lim&&i==top);
	}
	//不受限才记录
	if(!lim) f[pos][sta]=ans;
	return ans; 
} 
ll solve(ll x){
	memset(f,-1,sizeof(f));//不要忘记初始化 
	int cnt=0;
	while(x) a[++cnt]=x%10,x/=10;
	//lim始终为1
	//sta初始值根据题来定
	return dfs(pos,0,1); 
}

字符串算法

马拉车 manacher

void work(){
	n=s.size();
	string str="$";
	up(i,0,n-1){
		str+="#";
		str+=s[i];
	}
	str+="#&";
	s=str;
	n=s.size();
}
void HorsePullCar(){
	up(i,1,n-1){
		if(i<r) p[i]=min(p[(c<<1)-i],r-i);
		else p[i]=1;
		while(s[i+p[i]]==s[i-p[i]]) p[i]++;
		if(p[i]+i>r){
			r=p[i]+i;
			c=i;
		} 
	}
}
posted @ 2025-10-04 15:32  CrossBow_EXE  阅读(12)  评论(0)    收藏  举报
d125ec3a-002b-4467-d68f-08dbc3e79a09