preparing

模板汇总

洛谷的【模板】题
按照难度排序
题单

P3367 \(\color{#F39C11}{【模板】并查集}\)

大意

开始有\(n\)个元素,每个元素初始时在一个单独的集合里。接下来\(m\)次操作,将\(x,y\)所在的集合合并或者判断\(x,y\)是否在一个集合里。

思路

代码

#include<bits/stdc++.h>
using namespace std;
int i,j,k,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(i=1;i<=n;i++)
        f[i]=i;
    for(i=1;i<=m;i++){
        cin>>p1>>p2>>p3;
        if(p1==1)
            f[find(p2)]=find(p3);
        else
            if(find(p2)==find(p3))
                printf("Y\n");
            else
                printf("N\n");
    }
    return 0;
}

P1226 \(\color{#F39C11}{【模板】快速幂||取余运算}\)

大意

给定自然数\(a,b,p\),求\(a^b\bmod p\)

思路

因为\(a^b\bmod p=\begin{cases}(a^{\left\lfloor\frac{b}{2}\right\rfloor})^2&b\bmod 2 = 0\\(a^{\left\lfloor\frac{b}{2}\right\rfloor})^2 \times a& b\bmod 2 = 1\end{cases}\),考虑递归求解。

代码

#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
ll a,b,p;
ll qp(ll di,ll ci,ll mod){
	if(ci==0){
		return 1;
	}
	ll ans=qp(di,ci/2,mod)%mod;
	ans=ans*ans%mod;
	if(ci&1){
		ans=ans*a%mod;
	}
	return ans;
}
int main(){
	scanf("%lld%lld%lld",&a,&b,&p);
	printf("%lld^%lld mod %lld=%lld",a,b,p,qp(a,b,p));
	return 0;
}

P3383\(\color{#F39C11}{【模板】线性筛素数}\)

大意

\(q\)次询问,每次给定整数\(k\),求第\(k\)大的素数(所求素数\(\;\le 10^8\))。

思路

节选自2021CSP-J1

此处\(a,b\)数组即为欧拉筛,\(a\)记录是否被访问,\(b\)记录目前搜到的有素数。
自行搜索欧拉筛

代码

#include<iostream>
#include<cstdio>
#define maxn 100000005
using namespace std;
int n,q,k;
bool vis[maxn];
int prime[maxn],cnt=0;
int main(){
	scanf("%d%d",&n,&q);
	for(int i=2;i<=n;i++){
		if(!vis[i]){
			vis[i]=1;
			prime[++cnt]=i;
		}
		for(int j=1;j<=cnt&&i*prime[j]<maxn;j++){
			vis[i*prime[j]]=1;
		}
	}
	while(q--){
		scanf("%d",&k);
		printf("%d\n",prime[k]);
	}
	return 0;
}

P3366\(\color{#F39C11}{【模板】最小生成树}\)

大意

给定一无向图,输出最小生成树的边权和,若不连通输出\(orz\)

思路

\(Kruskal\) 算法)按边权从小到大枚举边,用并查集维护是否已经在最小生成树中。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#define maxn 200005
using namespace std;
int n,m,cnt,ans;
int fa[maxn];
int find(int x){
	if(fa[x]==x) return x;
	return fa[x]=find(fa[x]);
}
struct node{
	int from,to,dis;
}a[maxn];
bool cmp(node a,node b){
	return a.dis<b.dis;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		fa[i]=i;
	}
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&a[i].from,&a[i].to,&a[i].dis);
	}
	sort(a+1,a+1+m,cmp);
	for(int i=1;i<=m;i++){
		if(find(a[i].from)!=find(a[i].to)){
			fa[find(a[i].from)]=find(a[i].to);
			cnt++;
			ans+=a[i].dis;
		}
		if(cnt==n-1){
			break;
		}
	}
	if(cnt!=n-1){
		printf("orz");
		return 0;
	}
	printf("%d",ans);
	return 0;
}

P3378\(\color{#F39C11}{【模板】堆}\)

大意

给定一初始为空的序列,维护数据结构满足以下操作:插入、删除最小数据、输出最小数据。

思路

维护\(STL\)优先队列即可。

代码

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int n,opt,x;
priority_queue<int,vector<int>,greater<int> >q;
int main(){
	scanf("%d",&n);
	while(n--){
		scanf("%d",&opt);
		if(opt==1){
			scanf("%d",&x);q.push(x);
		}else if(opt==2){
			printf("%d\n",q.top());
		}else if(opt==3){
			q.pop();	
		}
	}
	return 0;
}

P3370\(\color{#F39C11}{【模板】字符串哈希}\)

大意

给定\(n\)个字符串,输出有多少个不同的。

思路

\(map\)维护即可。

代码

#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
int n,ans;
string a;
map<string,int> mp;
int main(){
	scanf("%d",&n);
	while(n--){
		cin>>a;
		if(!mp[a]){
			mp[a]=1;
			ans++;
		}
	}
	printf("%d",ans);
	return 0;
}

P1177\(\color{#F39C11}{【模板】快速排序}\)

大意

输入\(n\)个数,排序后升序输出

思路

无。

代码

#include<iostream>
#include<cstdio>
#define maxn 100005
using namespace std;
int n,a[maxn];
void quicksort(int l,int r){
	int i=l,j=r,temp=a[(l+r)/2];
	while(i<=j){
		while(a[i]<temp){
			i++;
		}
		while(a[j]>temp){
			j--;
		}
		if(i<=j){
			swap(a[i],a[j]);
			i++;
			j--;
		}
	}
	if(l<j) quicksort(l,j);
	if(r>i) quicksort(i,r);
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	quicksort(1,n);
	for(int i=1;i<=n;i++){
		printf("%d ",a[i]);
	}
	return 0;
}
/*
5
3 2 4 5 1
*/

P1886\(\color{#F39C11}{滑动窗口 /【模板】单调队列}\)

大意

有一长\(n\)的序列\(a\),给定正整数\(k\),分别求\(i\)\(1\)\(n-k+1\)\(\left[i,i+k-1\right]\)区间的最小\(\&\)大值。

思路

思路见此

代码

#include<iostream>
#include<cstdio>
#define maxn 1000005
using namespace std;
int n,k;
int a[maxn];
int q1[maxn],q2[maxn],h1=1,t1=0,h2=1,t2=0;//q1维护最大值,q2维护最小值 
int ans1[maxn],ans2[maxn];
void push1(int x,int l){
	while(t1>=h1&&a[x]>a[q1[t1]]){
		t1--;
	}
	q1[++t1]=x;
	while(t1>=h1&&q1[h1]<l){
		h1++;
	}
}
void push2(int x,int l){
	while(t2>=h2&&a[x]<a[q2[t2]]){
		t2--;
	}
	q2[++t2]=x;
	while(t2>=h2&&q2[h2]<l){
		h2++;
	}
}
int main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	q1[++t1]=1;
	q2[++t2]=1;
	for(int i=2;i<=k;i++){
		push1(i,-1);
		push2(i,-1);
	}
	ans1[1]=q1[h1];
	ans2[1]=q2[h2];
	for(int i=k+1;i<=n;i++){
		push1(i,i-k+1);
		push2(i,i-k+1);
		ans1[i-k+1]=q1[h1];
		ans2[i-k+1]=q2[h2];
	}
	for(int i=1;i<=n-k+1;i++){
		printf("%d ",a[ans2[i]]);
	}
	printf("\n");
	for(int i=1;i<=n-k+1;i++){
		printf("%d ",a[ans1[i]]);
	}
	return 0;
}

P3382\(\color{#FFC116}{【模板】三分法}\)

大意

给定一函数和区间\([l,r]\),求\(x\)使得函数在\([l,x]\)递增,在\([x,r]\)递减。

思路及相应代码

\[a_na^n+a_{n-1}a^{n-1}+…+a_1a+a_0 = (…((a_nx+a_{n-1})x+a_{n-2})x+…+a_1)x+a_0 \]

  1. 三分法
    每次找到区间的两个三等分点\(lmid\)\(rmid\),若\(f(lmid)<f(rmid)\)则在\([lmid,r]\)范围找,否则在\([l,rmid]\)范围找
#include<iostream>
#include<cstdio>
#define maxn 25
#define eps (1e-7)
using namespace std;
int n;
double l,r,lmid,rmid;
double a[maxn];
double f(double x){
	double ans=a[n];
	for(int i=n-1;i>=0;i--){
		ans=ans*x+a[i];
	}
	return ans;
}
int main(){
	scanf("%d%lf%lf",&n,&l,&r);
	for(int i=n;i>=0;i--){
		scanf("%lf",&a[i]);
	}
	while(r-l>=eps){
		lmid=l+(r-l)/3;
		rmid=r-(r-l)/3;
		if(f(lmid)<f(rmid)){
			l=lmid;
		}else{
			r=rmid-eps;
		}
	}
	printf("%.5lf",l);
	return 0;
}
  1. 求导\(+\)二分
    令原函数\(f\)的导数为\(f'\),所以只需要找\([l,r]\)区间内\(f'\)的零点即可。注意此时我们最好用以下式子:

\[f'(x)=\lim\limits_{\Delta x\rightarrow0}{\dfrac{f(x+\Delta x)-f(x)}{\Delta x}} \]

#include<iostream>
#include<cstdio>
#define maxn 25
#define eps (1e-10)
using namespace std;
int n;
double l,r,mid;
double a[maxn];
double f(double x){
	double ans=a[n];
	for(int i=n-1;i>=0;i--){
		ans=ans*x+a[i];
	}
	return ans;
}
double derivative(double x){
	return (f(x+eps)-f(x))/eps;
}
int main(){
	scanf("%d%lf%lf",&n,&l,&r);
	for(int i=n;i>=0;i--){
		scanf("%lf",&a[i]);
	}
	while(r-l>eps){
		mid=(l+r)/2;
		if(derivative(mid)>0) l=mid;
		else r=mid;
	}
	printf("%.5lf",mid);
	return 0;
}

P3374\(\color{#FFC116}{【模板】树状数组 1}\)

posted @ 2021-10-24 16:19  qzhwlzy  阅读(61)  评论(0)    收藏  举报