电子学会五级-分治算法
电子学会五级-分治算法
快速排序
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;
}
作者:newcode 更多资源请关注纽扣编程微信公众号
从事机器人比赛、机器人等级考试、少儿scratch编程、信息学奥赛等研究学习