个人学习笔记平台,欢迎大家交流

红叶~

Be humble, communicate clearly, and respect others.

第一次刷题笔记

Acwing刷题笔记

快速排序模板

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 100010;
int q[N];
int n;

void quick_sort(int a[], int l, int r) {
    if(l >= r)  return;
    int x = a[(l + r) /2], i = l - 1, j = r + 1;
    while(i < j) {
        do i++ ; while(a[i] < x);
        do j--; while(a[j] > x);
        if(i < j) swap(a[i], a[j]);
    }
    quick_sort(a, l, j);
    quick_sort(a ,j + 1, r);
}
int main() {
    cin >> n;
    for(int i = 0;i < n;i++)    scanf("%d", &q[i]);
    quick_sort(q, 0, n - 1);
    for(int i = 0;i < n;i++)    cout << q[i] << " ";
    return 0;
}

Acwing786 第k个数

https://www.acwing.com/activity/content/problem/content/820/
题目描述:给定一个长度为 n 的整数数列,以及一个整数 k,请用快速选择算法求出数列从小到大排序后的第 k 个数。
思路 利用快速排序解题,快速排序每一轮结束后,以中心元素 x(下标为j) 为界,左边是小于等于x的数,右边是大于等于x的数。

  • 如果 j+1-l >= k,说明第 k 个数在中心点的左边(l, j),那么可以直接递归左边,右边就不用管了。
  • 反正说明第k个数在中心点右边那一块,递归右边(j+1,r),但 k 变成k - (j - l + 1),即减去左边那段的数(包括中心点),当最后递归到一个点l >= r说明找到了数,返回q[l]
    AC代码:
#include<iostream>
using namespace std;

const int N = 100010;
int a[N];
int quick_sort(int q[],int l,int r,int k) {
    if(l >= r ) return q[l];
    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]);
    }
    if(j + 1 -l >=k)   return quick_sort(q, l, j, k);
    else return quick_sort(q, j + 1, r, k - (j - l + 1));
}
int main() {
    int n, m;
    cin >> n >> m;
    for(int i = 0 ;i< n;i++)    scanf("%d",&a[i]);
    cout << quick_sort(a, 0, n - 1, m);

    return 0;
}

归并排序模板

分而治之的思想

思路 : 归并排序是把一些数一直分成两半,其中的一般继续分成两半....,最后合并成有序序列的过程
如:
6 2 1 5 4 3 7
(6 2 1 5) (4 3 7)
(6 2) (1 5) (4 3) 7
(6)(2) (1)(5) (4)(3)(7) 分解到单个数了,接下来就是合并
合并
(2 6) (1 5) (3 4) (7)
(1 2 5 6) (3 4 7)
(1 2 3 4 5 6 7)

#include <iostream>
#include <cmath>
using namespace std;

const int N = 100010;
int q[N];

void merge(int a[], int l1, int r1, int l2, int r2) {
    int i = l1, j = l2;
    int index = 0;
    int temp[r2 - l1 + 1];
    while (i <= r1 && j <= r2) {
        if (a[i] <= a[j])
            temp[index++] = a[i++];
        else
            temp[index++] = a[j++];
    }
    while (i <= r1)
        temp[index++] = a[i++];
    while (j <= r2)
        temp[index++] = a[j++];
    for (int k = 0; k < index; k++)
        a[l1 + k] = temp[k];
}

void mergeSort(int A[], int left, int right) {
    if (left >= right)
        return;
    int mid = (left + right) / 2;
    mergeSort(A, left, mid);
    mergeSort(A, mid + 1, right);
    merge(A, left, mid, mid  + 1, right);
}

int main() {

    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
        scanf("%d", &q[i]);
    mergeSort(q, 0, n - 1);
    for (int i = 0; i < n; i++)
        cout << q[i] << " ";
    return 0;
}

逆序对的数量

题目:给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量。

逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i<j 且 a[i]>a[j],则其为一个逆序对;否则不是。
思路:利用归并排序合并的时候,左边两个序列都是有序的,设左右两个序列abij分别指向两个序列的左边。

  • 当左边序列出现a[i] > b[j],那么序列aa[i]后面的数也会大于b[j],都是逆序数对,有r1-i+1个。
  • 因为左边序列a[i]后面的数已经算到逆序对中了,但是a[i]还有用,比较下一个b[j]。此时j++,比较下一个数因为可能a[i] > b[j],也有逆序对。
#include <iostream>
#include <cmath>
#define ll long long
using namespace std;
const int N = 100010;
int q[N];
ll ans = 0;
void merge(int a[], int l1, int r1, int l2, int r2) {
    int i = l1, j = l2;
    int index = 0;
    int temp[r2-l1+1];
    while (i <= r1 && j <= r2) {
        if (a[i] <= a[j])
            temp[index++] = a[i++];
        else
        {
            ans += r1 - i + 1;
            // 左边数组与右边数组对比,(i,.....) a[i] > a[j], i右边的数也会满足 > a[j]
            temp[index++] = a[j++];
        }

    }
    while (i <= r1)
        temp[index++] = a[i++];
    while (j <= r2)
        temp[index++] = a[j++];
    for (int k = 0; k < index; k++)
        a[l1 + k] = temp[k];
}

void mergeSort(int A[], int left, int right) {
    if (left >= right)
        return;
    int mid = (left + right) / 2;
    mergeSort(A, left, mid);
    mergeSort(A, mid + 1, right);
    merge(A, left, mid, mid  + 1, right);
}

int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
        scanf("%d", &q[i]);
    mergeSort(q, 0, n - 1);
    cout << ans;
    return 0;
}

高精度加法模板

#include <iostream>
#include <vector>

using namespace std;

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;
}

int main()
{
    string a, b;
    vector<int> A, B;
    cin >> 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');

    auto C = add(A, B);

    for (int i = C.size() - 1; i >= 0; i -- ) cout << C[i];
    cout << endl;

    return 0;
}

高精度减法模板

#include <iostream>
#include <vector>

using namespace std;
// 比较两数大小
bool cmp(vector<int> &A, vector<int> &B)
{
    if (A.size() != B.size()) return A.size() > B.size();

    for (int i = A.size() - 1; i >= 0; i -- )
        if (A[i] != B[i])
            return A[i] > B[i];

    return true;
}

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;
}

int main()
{
    string a, b;
    vector<int> A, B;
    cin >> 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');

    vector<int> C;

    if (cmp(A, B)) C = sub(A, B);
    else C = sub(B, A), cout << '-';

    for (int i = C.size() - 1; i >= 0; i -- ) cout << C[i];
    cout << endl;

    return 0;
}

高精度乘法

思路\(a_4a_3a_2a_1a_0\) 用十进制表示是 \(a_4∗10^4+a_3∗10^3+a_2∗10^2+a_1∗10+a_0∗10^0\)
\(b_5b_4b_3b_2b_1b_0\) 表示为 \(b_5∗10^5+b_4∗10^4+b_3∗10^3+b_2∗10^2+b_1∗10+b_0∗10^0\)
那么两数相乘,可以直接用前面的数相乘,再乘以10的次方即可,且10的次方和下标的和一致,然后相加起来就可以得出结果

#include<iostream>
#include<cstring>
#include<vector>
using namespace std;

vector<int> mul(vector<int>& A, vector<int>& B) {
    vector<int> C(A.size() + B.size(), 0);

    for(int i = 0;i < A.size();i++)
        for(int j = 0;j < B.size();j++)
            C[i + j] += A[i] * B[j];    // C = C[i] * 10^i
    int t = 0; // 进位
    for(int i = 0; i < C.size(); i++) {
        t += C[i];
        C[i] = t % 10;
        t /= 10;
    }
    while(C.size() > 1 && C.back() == 0)    C.pop_back(); // 去除前导0     
    return C;
}

int main() {
    string a,b;
    cin >> a >> b;
    vector<int> A,B;
    for(int i = a.length() - 1; i >= 0;i--) A.push_back(a[i] - '0');
    for(int i = b.length() - 1;i >= 0;i--)   B.push_back(b[i] - '0');
    vector<int> c = mul(A, B);
    for(int i = c.size() - 1; i >= 0;i--)   cout << c[i];
    return 0;
}

高精度除法

https://cdn.jsdelivr.net/gh/moon-Light404/my-picGo@master/img/202112041558375.png

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

vector<int> div(vector<int> A, int B, int& r) {
    vector<int> C;
    for(int i = 0;i < A.size();i++) {
        r = r * 10 + A[i];
        C.push_back(r / B);
        r = r % B;
    }
    reverse(C.begin(), C.end()); // 逆转去除最高位的0
    while(C.size() > 1 && C.back() == 0)  C.pop_back();
    return C;
}

int main() {
    string s1;
    cin >> s1;
    int B, r = 0;
    cin >> B;
    vector<int> A;
    for(int i = 0; i < s1.size(); i++)  A.push_back(s1[i] - '0'); // 除法从高位开始算
    vector<int> c = div(A, B, r);
    for(int i = c.size() - 1;i >= 0;i--) cout << c[i];
    cout << endl;
    cout << r;
    return 0;
}
posted @ 2021-12-04 15:08  红叶~  阅读(33)  评论(0编辑  收藏  举报