电子学会五级-分治算法

电子学会五级-分治算法
快速排序
https://www.luogu.com.cn/problem/P1177

#include<bits/stdc++.h>
using namespace std;

const int MAXN=1e5+5;
int a[MAXN],n;
/*
	以L R 中间随机数分成两部分
	把左边比中间数大的数和右边比中间数小的数交换
	递归左半部分
	递归右半部分 
*/
void quickSort(int L,int R){
	int i=L,j=R;
	int mid=a[L+rand()%(R-L+1)];
	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(R>i) quickSort(i,R);
}

int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	quickSort(0,n-1);
	for(int i=0;i<n;i++){
		cout<<a[i]<<" ";
	}
	return 0;
}

逆序对
https://www.luogu.com.cn/problem/P1908

#include<bits/stdc++.h>
using namespace std;

const int MAXN=5e5+5;
int a[MAXN],temp[MAXN],n;
//50w特殊情况下会有(1+50w)*50/2种逆序对 所以会超int 
long long ans;//5 4 3 2 1   5种 4种  3种 2种 1种  (1+5)*5/2种 
/*
	每次取两边最小的一个放入临时数组
	左右区间未放入临时数组的放入
	copy合并好的临时数组到a数组 
*/ 
void merge(int L,int R,int mid){
	//i左半边数组下标  j右半边数组下标  k临时数组下标 
	int i=L,j=mid+1,k=L;
	while(i<=mid && j<=R){//左右部分每次取小的放入临时数组 
		if(a[i]>a[j]){//左边>右边 
			temp[k++]=a[j++];//右边a[j]放入临时数组
			//i~mid都比a[j]大 所以左边和a[j]组成mid-i+1个逆序对 
			ans+=mid-i+1;
		}else{ 
			temp[k++]=a[i++];//左边放入临时数组 
		}
	}
	while(i<=mid) temp[k++]=a[i++];//左边有剩余未放入临时数组,继续放入 
	while(j<=R)   temp[k++]=a[j++];//右边有剩余未放入临时数组,继续放入
	for(int i=L;i<=R;i++){//本区间排序好的temp数组放入a数组 
		a[i]=temp[i];
	}
}

/*
	L~R 中间分左右区间 合并排序 
*/ 
void mergeSort(int L,int R){
	//出口 
	if(L>=R){
		return;
	}
	//分 
	int mid=(L+R)/2;
	mergeSort(L,mid);
	mergeSort(mid+1,R);
	//治 
	merge(L,R,mid);
}

int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	mergeSort(0,n-1);
	cout<<ans;
}

快速幂||取余运算
https://www.luogu.com.cn/problem/P1226

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll fastPower(ll a,ll b,ll p){
	if(b==0){
		return 1%p;
	}
	ll ret = 1;
	while(b>0){
		if(b%2==0){//指数是偶数 
			b=b/2;//指数/2 
			a=a*a%p;//底数相乘 
		}else{//指数是奇数 
			b=b-1;//变成偶数 
			ret=ret*a%p;//这一次乘以底数即为原来的数 
			b=b/2;//变成偶数后指数/2 
			a=a*a%p;//底数相乘 
		}
	}
	return ret;
}
int main(){
	int a,b,p;
	cin>>a>>b>>p;
	ll ans = fastPower(a,b,p);
	cout<<a<<"^"<<b<<" mod "<<p<<"="<<ans;
}

优化1-缩减重复代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll fastPower(ll a,int b,int p){
	if(b==0){
		return 1%p;
	}
	ll ret = 1;
	while(b>0){
		if(b%2==1){//指数是奇数 
			ret=ret*a%p;//奇数乘一次当前底到ret中 
		}
		b=b/2;//指数/2
		a=a*a%p;//底数相乘 
	}
	return ret;
}
int main(){
	int a,b,p;
	cin>>a>>b>>p;
	ll ans = fastPower(a,b,p);
	cout<<a<<"^"<<b<<" mod "<<p<<"="<<ans;
}

优化2-位运算

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll fastPower(ll a,int b,int p){
	if(b==0){
		return 1%p;
	}
	ll ret = 1;
	while(b>0){
		if(b&1){//指数是奇数 
			ret=ret*a%p;//奇数乘一次当前底到ret中 
		}
		b=b>>1;//指数/2
		a=a*a%p;//底数相乘 
	}
	return ret;
}
int main(){
	int a,b,p;
	cin>>a>>b>>p;
	ll ans = fastPower(a,b,p);
	cout<<a<<"^"<<b<<" mod "<<p<<"="<<ans;
}

分治递归法

#include<cstdio>
long long a,b,p;

/*
	递归计算a的p次幂
	每次b缩小为原来的1/2  ans=a*a
	如果b为奇数 ans再乘一次a 
*/
long long qpow(int a,int b){
	if(b==1){
		return a;
	}else if(b==0){
		return 1;
	}else{
		//递归计算 指数范围缩小为原来1/2 
		long long temp=qpow(a,b/2)%p; 
		//temp*temp 则为指数为b的结果 
		long long ans=(temp%p*temp%p)%p;
		if(b%2==1){//b为奇数时 需乘一次底数 
			ans=(ans%p*a%p)%p;
		}
		ans=ans%p;//和p取余 
		return ans;
	}
} 
int main(){
	scanf("%lld%lld%lld",&a,&b,&p);
	long long ans=qpow(a,b);
	printf("%lld^%lld mod %lld=%lld",a,b,p,ans);
	return 0;
}

最大子段和
https://www.luogu.com.cn/problem/P1115

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
#define inf 0x3f3f3f3f
int a[N],n;
/*
	处理L~R范围内的数 
*/
int solve(int L,int R){
	if(L>=R)return a[L];//不能继续拆分为止 
	int mid=(L+R)/2;
	int res=max(solve(L,mid),solve(mid+1,R));//左右部分连续最大值中的最大的 有可能产生在左部分 也有可能产生在右部分 
	int maxL=-inf,maxR=-inf,sum=0;
	for(int i=mid;i>=L;i--){//左边整个部分 
		sum+=a[i];
		maxL=max(maxL,sum);
	}
	sum=0;
	for(int i=mid+1;i<=R;i++){//右边整个部分 
		sum+=a[i];
		maxR=max(maxR,sum);
	}
	return max(maxL+maxR,res);//maxL+maxR表示左右所有数连续  和RES 左 右 部分取最大 
}

int main(){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	cout<<solve(1,n);
	return 0;
}

P1923 【深基9.例4】求第 k 小的数
https://www.luogu.com.cn/problem/P1923
快速排序

#include<bits/stdc++.h>
using namespace std;

const int N=5e6+5;
int n,k;
int a[N];

void quickSort(int L,int R){
	int i=L,j=R;
	int mid=a[L+(R-L)/2];
	while(i<=j){
		while(a[i]<mid) i++;
		while(a[j]>mid) j--;
		if(i<=j){
			swap(a[i],a[j]);
			i++;
			j--;
		}
	}
	if(k<=j) quickSort(L,j);//在左区间只需要搜左区间
	else if(i<=k) quickSort(i,R);//在右区间只需要搜右区间
	else{//如果在中间区间直接输出
		printf("%d",a[j+1]);
		exit(0);
	}
}

int main(){
	scanf("%d%d",&n,&k);
	for(int i=0;i<n;i++){
		scanf("%d",&a[i]);
	}
	quickSort(0,n-1);
	return 0;
}

STL-nth_element 实现

C++ nth_element()用法详解
https://www.cnblogs.com/myeln/articles/16872875.html

#include<bits/stdc++.h>
using namespace std;

const int N=5e6+5;
int n,k;
int a[N];

int main(){
	scanf("%d%d",&n,&k);
	for(int i=0;i<n;i++){
		scanf("%d",&a[i]);
	}
	//前面到k下标为止都比k小 类似快速排序 
	nth_element(a,a+k,a+n);//第k小的数 从0开始计算  k=1表示第2小的数 
	printf("%d",a[k]);
	return 0;
}

集合求和
https://www.luogu.com.cn/problem/P2415

posted @ 2022-10-16 17:11  new-code  阅读(46)  评论(0编辑  收藏  举报