Chapter 1 basic algorithm

sort

Quick sort
The core idea of fast platoon is divide and conquer. Choose one as a sentry, so that the number less than or equal to it is on the left and the number greater than or equal to it is on the right
The time complexity is n(logn)

The steps are roughly divided into the following three steps:

  • Determine the dividing point
  • Adjustment interval
  • Recursive processing of left and right segments

y God template:

void quick_sort(int q[], int l, int r)
{
    if (l >= r) return;//The number of elements is one

    int i = l - 1, j = r + 1, x = q[l + r >> 1];
    while (i < j)
    {
        do i ++ ; while (q[i] < x);
        do j -- ; while (q[j] > x);
        if (i < j) swap(q[i], q[j]);
    }
    quick_sort(q, l, j), quick_sort(q, j + 1, r);
}

General template:

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e6+10;

int n;
int a[N];

void quick_sort(int q[],int l,int r)
{
    if(l>=r) return;
    int i=l-1,j=r+1,x=q[l+r>>1];
    while(i<j)
    {
        do i++;while(q[i]<x);
        do j--;while(q[j]>x);
        if(i<j) swap(q[i],q[j]);
    }

    quick_sort(q,l,j);quick_sort(q,j+1,r);
}
int  main(void)
{
    scanf("%d",&n);
    
    for(int i=0;i<n;i++) scanf("%d",&a[i]);
    
    quick_sort(a,0,n-1);
    for(int i=0;i<n;i++) printf("%d ",a[i]);
    return 0;
}

Merge sort
The core idea of fast platoon is divide and conquer, but it takes the middle position as the dividing point, which is different from fast platoon. Fast platoon selects a number in the array as the dividing point.
The time complexity is n(logn)

The steps are roughly divided into three steps:

  • Determine the dividing point
  • Recursive sorting
  • Merge (merge into one)

y God template:

void merge_sort(int q[], int l, int r)
{
    if (l >= r) return;

    int mid = l + r >> 1;
    merge_sort(q, l, mid);
    merge_sort(q, mid + 1, r);

    int k = 0, i = l, j = mid + 1;
    while (i <= mid && j <= r)
        if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ];
        else tmp[k ++ ] = q[j ++ ];

    while (i <= mid) tmp[k ++ ] = q[i ++ ];
    while (j <= r) tmp[k ++ ] = q[j ++ ];

    for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
}

General template:

#include<cstdio>
using namespace std;
const int N=100010;
int a[N];
int tmp[N];
void merge_sort(int q[],int l,int r)
{
	if(l>=r) return;//The description has been divided into one by one
	int mid=l+r>>1;
	merge_sort(q,l,mid),merge_sort(q,mid+1,r);
	
	int k=0;
	int i=l;//Head of left section 
	int j=mid+1; //Head of right section
	while(i<=mid&&j<=r)
	{
		if(q[i]<=q[j]) tmp[k++]=q[i++];
		else tmp[k++]=q[j++];
	} 
	while(i<=mid) tmp[k++]=q[i++];
	while(j<=r) tmp[k++]=q[j++];
	for(i=l,j=0;i<=r;i++,j++) q[i]=tmp[j];
}
int main(void)
{
	int n; scanf("%d",&n);
	for(int i=0;i<n;i++) scanf("%d",&a[i]);
	merge_sort(a,0,n-1);
	for(int i=0;i<n;i++) printf("%d ",a[i]);
	puts("");
	return 0;
}

Dichotomy

Integer dichotomy

If the integer is divided into two parts, we can judge whether r=mid or l=mid according to check()
Use this method to judge whether to add 1

y God template:

bool check(int x) {/* ... */} // Check whether x meets certain properties

// The interval [l, r] is divided into [l, mid] and [mid + 1, r]:
int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;    // check() determines whether the mid satisfies the property
        else l = mid + 1;
    }
    return l;
}
// The interval [l, r] is divided into [l, mid - 1] and [mid, r]:
int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

Floating point binary

For the floating-point binary template, there is no need to judge whether to add 1 or not, because it is continuous.

y God template:

bool check(double x) {/* ... */} // Check whether x meets certain properties

double bsearch_3(double l, double r)
{
    const double eps = 1e-6;   // eps indicates accuracy, which depends on the accuracy requirements of the subject
    while (r - l > eps)
    {
        double mid = (l + r) / 2;
        if (check(mid)) r = mid;
        else l = mid;
    }
    return l;
}

high-precision

High precision addition

y God template:

// C = A + B, A >= 0, B >= 0
vector<int> add(vector<int> &A, vector<int> &B)
{
    if (A.size() < B.size()) return add(B, A);

    vector<int> C;
    int t = 0;
    for (int i = 0; i < A.size(); i ++ )
    {
        t += A[i];
        if (i < B.size()) t += B[i];
        C.push_back(t % 10);
        t /= 10;
    }

    if (t) C.push_back(t);
    return C;
}
vector<int> add(vector<int> &A,vector<int> &B)
{
    vector<int> C;
    int t=0;
    for(int i=0;i<A.size()||i<B.size();i++)
    {
        if(i<A.size()) t+=A[i];
        if(i<B.size()) t+=B[i];
        C.push_back(t%10);
        t/=10;
    }
    if(t) C.push_back(1);
    return C;
}

High precision subtraction

y God template:

// C = A - B, satisfying a > = B, a > = 0, b > = 0
vector<int> sub(vector<int> &A, vector<int> &B)
{
    vector<int> C;
    for (int i = 0, t = 0; i < A.size(); i ++ )
    {
        t = A[i] - t;
        if (i < B.size()) t -= B[i];
        C.push_back((t + 10) % 10);
        if (t < 0) t = 1;
        else t = 0;
    }

    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}

Complete instance:

#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
using namespace std;
bool cmp(vector<int> &A,vector<int> &B)
{
    if(A.size()>B.size()) return true;
    if(A.size()<B.size()) return false;
    for(int i=A.size()-1;i>=0;i--)
    {
        if(A[i]>B[i]) return true;
        if(A[i]<B[i]) return false;
    }
    return true;
}
vector<int> sub(vector<int> &A,vector<int> &B)
{
    vector<int> C;
    int t=0;
    for(int i=0;i<A.size();i++)
    {
        t=A[i]-t;
        if(i<B.size()) t=t-B[i];
        C.push_back( (t+10) %10);
        if(t<0) t=1;
        else t=0;
    }
    while(C.size()>1&&C.back()==0) C.pop_back();
    return C;
}
int main(void)
{
    string a,b; cin>>a>>b;
    vector<int>A,B;
    for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
    for(int i=b.size()-1;i>=0;i--) B.push_back(b[i]-'0');
    if(cmp(A,B))
    {
        auto C=sub(A,B);
        for(int i=C.size()-1;i>=0;i--) cout<<C[i];
    }
    else
    {
        auto C=sub(B,A);
        cout<<"-";
        for(int i=C.size()-1;i>=0;i--) cout<<C[i];
    }
}

High precision multiplication

y God template:

// C = A * b, A >= 0, b >= 0
vector<int> mul(vector<int> &A, int b)
{
    vector<int> C;

    int t = 0;
    for (int i = 0; i < A.size() || t; i ++ )
    {
        if (i < A.size()) t += A[i] * b;
        C.push_back(t % 10);
        t /= 10;
    }

    while (C.size() > 1 && C.back() == 0) C.pop_back();

    return C;
}

High precision Division

Note that division is different from others. We calculate from low to high.
Division is calculated from high position to high position.

y God template:

// A / b = C ... r, A >= 0, b > 0
vector<int> div(vector<int> &A, int b, int &r)
{
    vector<int> C;
    r = 0;
    for (int i = A.size() - 1; i >= 0; i -- )
    {
        r = r * 10 + A[i];
        C.push_back(r / b);
        r %= b;
    }
    reverse(C.begin(), C.end());
    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}

Prefix and

One dimensional prefix sum

y God template:

S[i] = a[1] + a[2] + ... a[i]
a[l] + ... + a[r] = S[r] - S[l - 1]

Complete code:

#include<cstdio>
#include<iostream>
using namespace std;
const int N=1e5+10;
int a[N];
int s[N];
int main(void)
{
    int n,m; cin>>n>>m;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
    while(m--)
    {
        int l,r; cin>>l>>r;
        cout<<s[r]-s[l-1]<<endl;
    }
    return 0;
}

2D prefix and

y God template:

S[i, j] = The first i that 's ok j The sum of all elements in the upper left part of the column grid
 with(x1, y1)Is the upper left corner,(x2, y2)The sum of the submatrix in the lower right corner is:
S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]

Complete code:

#include<cstdio>
#include<iostream>
using namespace std;
const int N=1010;
int n,m,q;
int a[N][N],s[N][N];
int main(void)
{
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			scanf("%d",&a[i][j]);
			s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
		}
	}
	while(q--)
	{
		int x1,y1,x2,y2;
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		printf("%d\n",s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]);
	}
	return 0;
}

Difference

Difference is an inverse operation of prefix sum.
We are going to construct an array b1,b2,b3. bring
b1=a1-a0; b2=a2-a1; b3=a3-a2;
So a1=b1=a1; a2=b1+b2=a2 a3=b3+b2+b1=a3;

If we want to add, we just need to add a c at the beginning and subtract c next to the last at the end.
Because it is a prefix and, so one plus a number, the others will be added

One dimensional difference
y God template:

Give interval[l, r]Each number in the plus c: B[l] += c, B[r + 1] -= c

Full code:

#include<iostream>
#include<cstdio>
using namespace std;
const int N=101000;
int a[N],b[N];
void insert(int l,int r,int c)
{
    b[l]+=c;
    b[r+1]-=c;
}
int main(void)
{
    int n,m;cin>>n>>m;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    
    for(int i=1;i<=n;i++) insert(i,i,a[i]);//Initialize differential array
    
    while(m--)
    {
        int l,r,c; cin>>l>>r>>c;
        insert(l,r,c);
    }
    for(int i=1;i<=n;i++) b[i]+=b[i-1];//Prefix Sum 
    
    for(int i=1;i<=n;i++) cout<<b[i]<<" ";
    return 0;
}

Two dimensional difference

y God template:

Give(x1, y1)Is the upper left corner,(x2, y2)Add to all elements in the submatrix in the lower right corner c: 
S[x1, y1] += c, S[x2 + 1, y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] += c

Full code:

#include<iostream>
#include<cstdio>
using namespace std;
const int N=1010;
int a[N][N],b[N][N];
void insert(int x1,int y1,int x2,int y2,int c)
{
    b[x1][y1]+=c;
    b[x2+1][y1]-=c;
    b[x1][y2+1]-=c;
    b[x2+1][y2+1]+=c;
}
int main(void)
{
    int n,m,q;cin>>n>>m>>q;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&a[i][j]);
        }
    }
    
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            insert(i,j,i,j,a[i][j]);//initialization
        }
    }
    
    while(q--)
    {
        int x1,y1,x2,y2,c;
        cin>>x1>>y1>>x2>>y2>>c;
        insert(x1,y1,x2,y2,c);
    }
    
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1];//Prefix and
        }
    }
    
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cout<<b[i][j]<<" ";
        }
        cout<<endl;
    }
    return 0;
}

Binary

y God template:

seek n The first k Digit number: n >> k & 1
 return n Last 1: lowbit(n) = n & -n

Double pointer

y God template:

for (int i = 0, j = 0; i < n; i ++ )
{
    while (j < i && check(i, j)) j ++ ;

    // Logic of specific problems
}
Classification of frequently asked questions:
    (1) For a sequence, maintain an interval with two pointers
    (2) For two sequences, maintain a certain order, such as merging two ordered sequences in merge sort

Discretization

y God template:

vector<int> alls; // Store all values to be discretized
sort(alls.begin(), alls.end()); // Sort all values
alls.erase(unique(alls.begin(), alls.end()), alls.end());   // Remove duplicate elements

// Find the discretized value corresponding to x by bisection
int find(int x) // Find the first position greater than or equal to x
{
    int l = 0, r = alls.size() - 1;
    while (l < r)
    {
        int mid = l + r >> 1;
        if (alls[mid] >= x) r = mid;
        else l = mid + 1;
    }
    return r + 1; // Map to 1, 2 n
}

Interval merging

y God template:

// Merge all intersecting intervals
void merge(vector<PII> &segs)
{
    vector<PII> res;

    sort(segs.begin(), segs.end());

    int st = -2e9, ed = -2e9;
    for (auto seg : segs)
        if (ed < seg.first)//Merge in the same way
        {
            if (st != -2e9) res.push_back({st, ed});//Not the initial value
            st = seg.first, ed = seg.second;
        }
        else ed = max(ed, seg.second);//merge

    if (st != -2e9) res.push_back({st, ed});//Last interval

    segs = res;
}

Keywords: C++ Algorithm

Added by sashi34u on Thu, 03 Mar 2022 15:42:46 +0200