ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

基础课 第一讲 基础算法

2021-10-27 13:04:42  阅读:222  来源: 互联网

标签:第一 int ed while mid 算法 alls 基础课 区间


快速排序

785.快速排序

排序看似简单,其实边界问题还挺麻烦

786.第k个数(快速选择\(O(n)\))

求数组中第k大的数

快速选择算法——只用递归一边的快排,复杂度 \(O(n)\)

在快速排序的某次递归中,记左区间有 \(L\) 个元素,右区间有 \(R\) 个元素。如果 \(k\le L\) 则递归左区间,找左区间中第 \(k\) 大的数。否则递归右区间,找右区间中第 \(k-L\) 大的数。

#include <bits/stdc++.h>
using namespace std;
const signed N = 1e5+10;

int a[N];

int qs(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]);
    }
    int L = j-l+1;
    return k <= L ? qs(q,l,j,k) : qs(q,j+1,r,k-L);
}

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

    return 0;
}

归并排序

787.归并排序
788.逆序对的数量

luogu P1908 逆序对

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const signed N = 5e5+10;

int a[N];

int tmp[N];
ll ms(int l, int r)
{
    if(l >= r) return 0;
    int mid = l + r >> 1;
    ll res = ms(l, mid) + ms(mid + 1, r); //核心

    int k = 0, i = l, j = mid + 1;
    while(i <= mid && j <= r)
        if (a[i] <= a[j]) tmp[k++] = a[i++];
        else tmp[k++] = a[j++], res += mid - i + 1; //核心
    while(i <= mid) tmp[k++] = a[i++];
    while(j <= r) tmp[k++] = a[j++];
    for(i = l, j = 0; i <= r; i++, j++) a[i] = tmp[j];

    return res;
}

signed main()
{
    int n; scanf("%d", &n);
    for(int i = 0; i < n; i++) scanf("%d", &a[i]);
    printf("%lld", ms(0, n-1));

    return 0;
}

二分

789.数的范围

注意找不到的话 \(l==\) 区间右端点

790.数的三次方根

高精度

四题都锁了,不想写了

791.高精度加法
792.高精度减法
793.高精度乘法
794.高精度除法

前缀和与差分

795.前缀和
796.子矩阵的和

二维前缀和 S[i][j] = a[i][j] + S[i-1][j] + S[i][j-1] - S[i-1][j-1]

797.差分

可以把输入 a[i] 视为把区间 \([i,i]\) 中的数加上 a[i] ,从而用区间加建立差分数组

#include <bits/stdc++.h>
using namespace std;
const signed N = 1e5+10;
int b[N];
void ins(int l, int r, int x) {b[l] += x; b[r+1] -= x; }
signed main()
{
    int n, m; cin >> n >> m;
    for(int i = 1; i <= n; i++)
    {
        int tmp; cin >> tmp;
        ins(i,i,tmp);
    }
    while(m--)
    {
        int l ,r, x; cin >> l >> r >> x;
        ins(l,r,x);
    }
    for(int i = 1; i <= n; i++)
    {
        b[i] += b[i - 1]; //求前缀和得到正常矩阵
        cout << b[i] << ' ';
    }

    return 0;
}

798.差分矩阵

原矩阵是差分矩阵的前缀和,某点加 c 会把这个点右下的数全加 c

对矩形 (x1,y1)(x2,y2) 中的元素加 c:

b[x1][y1]+=c, b[x2+1][y1]-=c, b[x1][y2+1]-=c, b[x2+1][y2+1]+=c

image

由差分矩阵得到正常矩阵:

b[i][j] += b[i-1][j] + b[i][j - 1] - b[i - 1][j - 1]

双指针算法

“单调关系”

799.最长连续不重复子序列
//j在i的左边,注意在i右移的同时,j也不能左移,是为“单调关系”
for(int i = 0, j = 0; i < n; i++)
{
    cnt[a[i]]++; //字符出现次数
    while(s[a[i]] > 1) s[a[j]--], j++;
    ans = max(ans, i - j + 1);
}
800.数组元素的目标和

输出满足 a[i] + b[j] == x 的所有 a[i]b[j] 。如果解唯一就能用双指针,否则不行,要用哈希(怎么做呢)

位运算

801.二进制中1的个数
while(x) x -= lowbit(x), ans++;

离散化

802.区间和

假定有一个无限长的数轴,数轴上每个坐标上的数都是0。

现在,我们首先进行 n 次操作,每次操作将某一位置x上的数加c。

接下来,进行 m 次询问,每个询问包含两个整数l和r,你需要求出在区间[l, r]之间的所有数的和。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef pair<int, int> PII;
const int N = 300010;
int n, m;
int a[N], s[N];
vector<int> alls;
vector<PII> add, query;
int find(int x){ //此函数可用lower_bound代替
    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; //从1开始方便前缀和
}
int main(){
    cin >> n >> m;
    for (int i = 0; i < n; i ++ ){
        int x, c;
        cin >> x >> c;
        add.push_back({x, c});
        alls.push_back(x);
    }
 
    for (int i = 0; i < m; i ++ ){
        int l, r;
        cin >> l >> r;
        query.push_back({l, r});
        alls.push_back(l);
        alls.push_back(r);
    }
    // 去重
    sort(alls.begin(), alls.end());
    alls.erase(unique(alls.begin(),alls.end()), alls.end());
    // 处理插入
    for (auto item : add){
        int x = find(item.first);
        a[x] += item.second;
    }
    // 预处理前缀和
    for (int i = 1; i <= alls.size(); i ++ ) s[i] = s[i - 1] + a[i];
    // 处理询问
    for (auto item : query){
        int l = find(item.first), r = find(item.second);
        cout << s[r] - s[l - 1] << endl;
    }
    return 0;
}

区间合并

803.区间合并

把有交集或端点相交的区间合并,输出合并后区间数

按左端点排序,逐个判断前后区间是否相交

sort(segs.begin(), segs.end());
int st = -2e9, ed = 2e9;
for(auto seg : segs)
    if(ed < seg.first)
    {
        if(st != 2e9) ans.push_back({st, ed});
        st = seg.first, ed = seg.second;
    }
    else ed = max(ed, seg.second);
if(st != 2e9) ans.push_back({st, ed});

标签:第一,int,ed,while,mid,算法,alls,基础课,区间
来源: https://www.cnblogs.com/wushansinger/p/15470073.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有