其他算法()

ST表

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+110;
int st[N][21],m,n,k[N];
int read(){
	int x=0,f=1;char c=getchar();
	while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
	while(c>='0' && c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
void build(){
	for(int i=1;i<=17;i++)
		for(int j=1;j<=n;j++)
			st[j][i]=max(st[j][i-1],st[j+(1<<i-1)][i-1]);//数组开大点防止越界
	return;
}
int l,r;
int main(){
//	cout<<(1<<17);可以先看看应该开多大
	n=read(),m=read();
	for(int i=1;i<=n;i++)st[i][0]=read();
	build();int now=0;
	for(int i=1;i<=n;i++){if((1<<now+1)<=i)now++;k[i]=now;}//预处理完后可以O(1)查询了。
	for(int i=1;i<=m;i++){
		l=read(),r=read();
		printf("%d\n",max(st[l][k[r-l+1]],st[r-(1<<k[r-l+1])+1][k[r-l+1]]));
	} 
	return 0;
} 

模拟退火

#include<bits/stdc++.h>
using namespace std;
const int N=1011;
int read(){
	int x=0,f=1;char c=getchar();
	while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
	while(c>='0' && c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
int n,x[N],y[N],w[N];
double nowx,nowy,ans,ansx,ansy;
double work(double tx,double ty){
	double energy=0;
	for(int i=1;i<=n;i++)
		energy+=sqrt((x[i]-tx)*(x[i]-tx)+(y[i]-ty)*(y[i]-ty))*w[i];
	return energy;
}
void SA(){
	nowx=ansx,nowy=ansy;//初始位置(继承上次最优解)YCE说:这里应该重新开始搜,否则容易陷入局部最优解。(正在验证)
	double T=3000;//初始温度 (影响搜索范围) 
	while(T>1e-16){//结束温度 
		double tx=nowx+(rand()*2-RAND_MAX)*T;
		double ty=nowy+(rand()*2-RAND_MAX)*T;//自己猜答案,温度越低越稳定
		double nwans=work(tx,ty);
		double de=nwans-ans;
		if(de<0){ansx=nowx=tx;ansy=nowy=ty;ans=nwans;}//更优解 
		else if(exp(-de/T)*RAND_MAX>rand()){//反正exp的范围为0~1,且越接近正解,越容易选,温度越低,越不容易选。
			nowx=tx,nowy=ty;
		}
		T*=0.995;//徐徐降温(影响搜索正确率) 
	}
	return;
}
void solve(){
	ansx=0,ansy=0,ans=work(nowx,nowy);//初始答案
	while((double)clock()/CLOCKS_PER_SEC<0.7)SA();//富贵TLE中求 
//	SA();SA();SA();
	return;
}
int main(){
	srand('F'+'J'+'L'+'o'+'v'+'e'+'J'+'C');
	n=read();for(int i=1;i<=n;i++){x[i]=read(),y[i]=read(),w[i]=read();}
	solve();
	printf("%.3lf %.3lf",ansx,ansy);
	return 0;
}

内存爆炸

你该检查一下自己是否MLE了。

#include<bits/stdc++.h>
using namespace std;
bool alarm1;//边界1(最上方)
const int N=1e6+110;
int st[N][210],m,n,k[N];
int read(){
	int x=0,f=1;char c=getchar();
	while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
	while(c>='0' && c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
void build(){
	for(int i=1;i<=17;i++)
		for(int j=1;j<=n;j++){
			st[j][i]=max(st[j][i-1],st[j+(1<<i-1)][i-1]);
			if(st[j+(1<<i-1)][i-1]==1e9+1)
				cout<<j<<" "<<i-1<<endl;
		}
	return;
}
int l,r;
bool alarm2;//边界2(最下方)
int main(){
	fprintf(stderr,"%0.3lf\n",abs(&alarm1-&alarm2)/1048576.0);//这是为了防止你没注释它(1048576=1024*1024)
//	cout<<(1<<17);
	n=read(),m=read();
	for(int i=1;i<=n;i++)st[i][0]=read();
	for(int i=n+1;i<=1e6;i++)st[i][0]=1e9+1;
	build();int now=0;
	for(int i=1;i<=n;i++){if((1<<now+1)<=i)now++;k[i]=now;}
	for(int i=1;i<=m;i++){
		l=read(),r=read();
		printf("%d\n",max(st[l][k[r-l+1]],st[r-(1<<k[r-l+1])+1][k[r-l+1]]));
	} 
	return 0;
} 

手动开栈

**东西让我考场费时1h(另一个**东西是树剖,我再打树剖我就是狗!!!)

工具->编译选项->"-Wl,--stack=998244353"

反悔贪心

反悔自动机:

即设计一种反悔策略,使得随便一种贪心策略都可以得到正解。

基本的设计思路是:每次选择直观上最接近全局最优解的贪心策略,若发现最优解不对,就想办法自动支持反悔策略。(这就是自动机的意思)

具体题目具体分析。一般需要反悔自动机的题都是通过差值巧妙达到反悔的目的。

反悔堆:

即通过堆(大根堆、小根堆)来维护当前贪心策略的最优解,若发现最优解不对,就退回上一步,更新最优解。

由于堆的性质,使得堆的首数据一定是最优的,这就可以实现快速更新最优解。

(摘自这里)

(例题见这里)

模拟费用流

好东西

代码风格

重载运算符:

MAT operator*(const MAT &A)const{
	MAT C;C.clear();
	for(int i=0;i<=4;i++)
		for(int j=0;j<=4;j++)
			for(int k=0;k<=4;k++)
				C.m[i][j]=min(C.m[i][j],A.m[i][k]+m[k][j]);
	return C;
}
bool operator<(const node &A)const{
	return A.dis<dis;
}

清晰的结构体包函数。

struct SegmentTree{
	struct node{ int l, r; Matrix val; } T[N<<2];
	void build(int p, int l, int r){
		T[p].l = l, T[p].r = r;
		if(l == r){
			for(int i = 0; i < 5; ++ i) T[p].val.a[i][i] = 0;
			if(s[l] == '2') T[p].val.a[0][0] = 1, T[p].val.a[0][1] = 0;
			if(s[l] == '0') T[p].val.a[1][1] = 1, T[p].val.a[1][2] = 0;
			if(s[l] == '1') T[p].val.a[2][2] = 1, T[p].val.a[2][3] = 0;
			if(s[l] == '7') T[p].val.a[3][3] = 1, T[p].val.a[3][4] = 0;
			if(s[l] == '6') T[p].val.a[3][3] = 1, T[p].val.a[4][4] = 1;
		} else {
			int mid = l + r >> 1;
			build(p<<1, l, mid); build(p<<1|1, mid+1, r);
			T[p].val = T[p<<1].val * T[p<<1|1].val; 
		}
	}
	Matrix query(int p, int l, int r){
		if(l <= T[p].l && T[p].r <= r) return T[p].val;
		int mid = T[p].l + T[p].r >> 1;
		if(r <= mid) return query(p<<1, l, r);
		if(mid < l) return query(p<<1|1, l, r);
		return query(p<<1, l, r) * query(p<<1|1, l, r);
	}
} Solver;

sqrt精度问题

long long x=sqrt((long long)n);
while((x+1)*(x+1)<=n)++x;
while(x*x>n)--x;

离散化

越是基础,越能决定成败
for(int i=1;i<=n;i++)lsh[i]=num[i]=read();
sort(lsh+1,lsh+n+1);
cnt=unique(lsg+1,lsh+n+1)-lsh-1;
for(int i=1;i<=n;i++){
	num[i]=lower_bound(lsh+1,lsh+cnt+1,num[i])-lsh;
}
————————

ST表

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+110;
int st[N][21],m,n,k[N];
int read(){
	int x=0,f=1;char c=getchar();
	while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
	while(c>='0' && c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
void build(){
	for(int i=1;i<=17;i++)
		for(int j=1;j<=n;j++)
			st[j][i]=max(st[j][i-1],st[j+(1<<i-1)][i-1]);//数组开大点防止越界
	return;
}
int l,r;
int main(){
//	cout<<(1<<17);可以先看看应该开多大
	n=read(),m=read();
	for(int i=1;i<=n;i++)st[i][0]=read();
	build();int now=0;
	for(int i=1;i<=n;i++){if((1<<now+1)<=i)now++;k[i]=now;}//预处理完后可以O(1)查询了。
	for(int i=1;i<=m;i++){
		l=read(),r=read();
		printf("%d\n",max(st[l][k[r-l+1]],st[r-(1<<k[r-l+1])+1][k[r-l+1]]));
	} 
	return 0;
} 

模拟退火

#include<bits/stdc++.h>
using namespace std;
const int N=1011;
int read(){
	int x=0,f=1;char c=getchar();
	while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
	while(c>='0' && c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
int n,x[N],y[N],w[N];
double nowx,nowy,ans,ansx,ansy;
double work(double tx,double ty){
	double energy=0;
	for(int i=1;i<=n;i++)
		energy+=sqrt((x[i]-tx)*(x[i]-tx)+(y[i]-ty)*(y[i]-ty))*w[i];
	return energy;
}
void SA(){
	nowx=ansx,nowy=ansy;//初始位置(继承上次最优解)YCE说:这里应该重新开始搜,否则容易陷入局部最优解。(正在验证)
	double T=3000;//初始温度 (影响搜索范围) 
	while(T>1e-16){//结束温度 
		double tx=nowx+(rand()*2-RAND_MAX)*T;
		double ty=nowy+(rand()*2-RAND_MAX)*T;//自己猜答案,温度越低越稳定
		double nwans=work(tx,ty);
		double de=nwans-ans;
		if(de<0){ansx=nowx=tx;ansy=nowy=ty;ans=nwans;}//更优解 
		else if(exp(-de/T)*RAND_MAX>rand()){//反正exp的范围为0~1,且越接近正解,越容易选,温度越低,越不容易选。
			nowx=tx,nowy=ty;
		}
		T*=0.995;//徐徐降温(影响搜索正确率) 
	}
	return;
}
void solve(){
	ansx=0,ansy=0,ans=work(nowx,nowy);//初始答案
	while((double)clock()/CLOCKS_PER_SEC<0.7)SA();//富贵TLE中求 
//	SA();SA();SA();
	return;
}
int main(){
	srand('F'+'J'+'L'+'o'+'v'+'e'+'J'+'C');
	n=read();for(int i=1;i<=n;i++){x[i]=read(),y[i]=read(),w[i]=read();}
	solve();
	printf("%.3lf %.3lf",ansx,ansy);
	return 0;
}

内存爆炸

你该检查一下自己是否MLE了。

#include<bits/stdc++.h>
using namespace std;
bool alarm1;//边界1(最上方)
const int N=1e6+110;
int st[N][210],m,n,k[N];
int read(){
	int x=0,f=1;char c=getchar();
	while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
	while(c>='0' && c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
void build(){
	for(int i=1;i<=17;i++)
		for(int j=1;j<=n;j++){
			st[j][i]=max(st[j][i-1],st[j+(1<<i-1)][i-1]);
			if(st[j+(1<<i-1)][i-1]==1e9+1)
				cout<<j<<" "<<i-1<<endl;
		}
	return;
}
int l,r;
bool alarm2;//边界2(最下方)
int main(){
	fprintf(stderr,"%0.3lf\n",abs(&alarm1-&alarm2)/1048576.0);//这是为了防止你没注释它(1048576=1024*1024)
//	cout<<(1<<17);
	n=read(),m=read();
	for(int i=1;i<=n;i++)st[i][0]=read();
	for(int i=n+1;i<=1e6;i++)st[i][0]=1e9+1;
	build();int now=0;
	for(int i=1;i<=n;i++){if((1<<now+1)<=i)now++;k[i]=now;}
	for(int i=1;i<=m;i++){
		l=read(),r=read();
		printf("%d\n",max(st[l][k[r-l+1]],st[r-(1<<k[r-l+1])+1][k[r-l+1]]));
	} 
	return 0;
} 

手动开栈

**东西让我考场费时1h(另一个**东西是树剖,我再打树剖我就是狗!!!)

工具->编译选项->"-Wl,--stack=998244353"

反悔贪心

反悔自动机:

即设计一种反悔策略,使得随便一种贪心策略都可以得到正解。

基本的设计思路是:每次选择直观上最接近全局最优解的贪心策略,若发现最优解不对,就想办法自动支持反悔策略。(这就是自动机的意思)

具体题目具体分析。一般需要反悔自动机的题都是通过差值巧妙达到反悔的目的。

反悔堆:

即通过堆(大根堆、小根堆)来维护当前贪心策略的最优解,若发现最优解不对,就退回上一步,更新最优解。

由于堆的性质,使得堆的首数据一定是最优的,这就可以实现快速更新最优解。

(摘自这里)

(例题见这里)

模拟费用流

好东西

代码风格

重载运算符:

MAT operator*(const MAT &A)const{
	MAT C;C.clear();
	for(int i=0;i<=4;i++)
		for(int j=0;j<=4;j++)
			for(int k=0;k<=4;k++)
				C.m[i][j]=min(C.m[i][j],A.m[i][k]+m[k][j]);
	return C;
}
bool operator<(const node &A)const{
	return A.dis<dis;
}

清晰的结构体包函数。

struct SegmentTree{
	struct node{ int l, r; Matrix val; } T[N<<2];
	void build(int p, int l, int r){
		T[p].l = l, T[p].r = r;
		if(l == r){
			for(int i = 0; i < 5; ++ i) T[p].val.a[i][i] = 0;
			if(s[l] == '2') T[p].val.a[0][0] = 1, T[p].val.a[0][1] = 0;
			if(s[l] == '0') T[p].val.a[1][1] = 1, T[p].val.a[1][2] = 0;
			if(s[l] == '1') T[p].val.a[2][2] = 1, T[p].val.a[2][3] = 0;
			if(s[l] == '7') T[p].val.a[3][3] = 1, T[p].val.a[3][4] = 0;
			if(s[l] == '6') T[p].val.a[3][3] = 1, T[p].val.a[4][4] = 1;
		} else {
			int mid = l + r >> 1;
			build(p<<1, l, mid); build(p<<1|1, mid+1, r);
			T[p].val = T[p<<1].val * T[p<<1|1].val; 
		}
	}
	Matrix query(int p, int l, int r){
		if(l <= T[p].l && T[p].r <= r) return T[p].val;
		int mid = T[p].l + T[p].r >> 1;
		if(r <= mid) return query(p<<1, l, r);
		if(mid < l) return query(p<<1|1, l, r);
		return query(p<<1, l, r) * query(p<<1|1, l, r);
	}
} Solver;

sqrt精度问题

long long x=sqrt((long long)n);
while((x+1)*(x+1)<=n)++x;
while(x*x>n)--x;

离散化

越是基础,越能决定成败
for(int i=1;i<=n;i++)lsh[i]=num[i]=read();
sort(lsh+1,lsh+n+1);
cnt=unique(lsg+1,lsh+n+1)-lsh-1;
for(int i=1;i<=n;i++){
	num[i]=lower_bound(lsh+1,lsh+cnt+1,num[i])-lsh;
}